/*----------------------------------------------------------------------------
 * Copyright (c) <2016-2019>, <Huawei Technologies Co., Ltd>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *---------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
 * Notice of Export Control Law
 * ===============================================
 * Huawei LiteOS may be subject to applicable export control laws and regulations, which might
 * include those applicable to Huawei LiteOS of U.S. and the country in which you are located.
 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such
 * applicable export control laws and regulations.
 *---------------------------------------------------------------------------*/
#include "omip.h"
#include "cJSON.h"
#include "omip_log.h"
#include "omip_uart.h"
#include "w25qxx.h"
#include "osal.h"
#include "hlink_user_api.h"
#include "hlink_packages.h"
#include "ble.h"
#include "main.h"
#include "securec.h"
#include "read_and_write_flash.h"
#include "los_memory.h"
#include "sdram.h"
#include "message_flow.h"
#include "point_read_write.h"
#include "bsp_api.h"
#include "hardware_com.h"
#include "app_common.h"
#include "hal_iwdg.h"
#include "hardware_com.h"
#include "hlink_log.h"
#include "mcu_log.h"


#define DEF_VAV_SN 			"H100309000032"  	//缺省SN //"HL1VAV11100309000029" 
#define PACKAGE_CACHE_LEN    4096
#define PER_BLOCK_SLEEP_TIME 300 //ms
#define TRANSFER_RESULT "transfer result"

static w25flash_t *g_flash_sn   =NULL; //FLASH中记录的设备SN结构
static w25flash_t *g_flash_dev  =NULL; //FLASH中记录的设备信息结构
static w25flash_t *g_flash_flow =NULL; //FLASH中记录的策略文件结构
static w25flash_t *g_flash_bin  =NULL; //FLASH中记录的MCU固件结构

#define OMIP_USER_RECV_BUF	4096

struct omip_app_conf{
    char  		 * appname;
    unsigned char  vc;
    omip_qos_level qos;
    unsigned char  support_auth;
    unsigned char  reserved;
    unsigned char  recv_buf[OMIP_USER_RECV_BUF]; //must 4 bytes alignment
};

#define MCU_COMMON_APP "mcu_omip_app"
#define MCU_DEVICE_SN  "HL104A02001E88888823"

#define MCU_BLE_APP_OFFLINE  0
#define MCU_BLE_APP_ONLINE   1

static struct omip_app_conf g_common_conf[] = {
    {MCU_COMMON_APP"0", OMIP_VC_CHANNEL4, OMIP_QOS_2, 0, 0, {0}},
#if OMIP_SUPPORT_PROXY 
    {MCU_COMMON_APP"1", OMIP_VC_CHANNEL6, OMIP_QOS_0, 1, 0, {0}},
#endif
};

#define JSON_REPORT_DATA  "{\r\n"  \
  "\"serviceId\": \"srvDataRpt\",\r\n"  \
  "\"data\": \"serviceObject\"\r\n"  \
  "}\r\n"  \
  "\r\n"

#define GET_JSON_ITEM(j,key,item,def_val)	(cJSON_GetObjectItem(j,key)==NULL? def_val:cJSON_GetObjectItem(j,key)->item)

#define SUPPORT_DEV_UPDATE           1
#define SUPPORT_EXT_DEV              0

typedef struct _file_mngr_trans //文件传输状态
{
	int  		  notice_mid;		//通知消息的MID
	char 		* file_buffer;		//文件缓存
	unsigned long notice_size;		//通知文件长度
	unsigned long received_size;	//接收实际长度
	int			  trans_status;		//当前传输状态
	int			  last_activetm;	//最后活跃时间
	void *		  ble_pack_taskid;	//蓝牙package包升级任务ID
	void *		  ble_ota_taskid;	//蓝牙固件升级任务ID
	unsigned int  ble_ota_res;		//蓝牙OTA时的回复标志
	unsigned int  ble_ota_tmout;	//蓝牙OTA时的超时时间
	char 		  checksum[HLINK_FILE_CHECK_SUM_LEN_MAX+1]; //文件校验
}file_mngr_trans;

char 		g_mcu_sn[64] 		= {0};
static char g_ble_version[32] 	= {0};

static moudle_online_info 	g_hlink_info = {0}; //模块上线信息
static file_mngr_notice 	g_notice_msg = {0}; //文件传输通知缓存
static file_mngr_trans		g_file_trans = {0}; //文件传输状态
static osal_semp_t 			Mutex_ble_handle;	//蓝牙OTA信号互斥量

#define PACKAGE_INVALIDE_ERRCODE 0XFFFF
int g_hlink_upgrade_result = PACKAGE_INVALIDE_ERRCODE;
static osal_semp_t 			g_hlink_ota_semp;
static void *g_mcu_log_upload_task_id = NULL;

extern UINT32 LOS_MemStatisticsGet(VOID *pPool, LOS_MEM_STATUS *pstStatus);
void device_manager_logfile_mcu_task_create(mcu_upload_logfile_direction upload_direction);

static void free_file_buff() //释放文件缓存
{
	OMIP_LOG_INFO( "free file type:%s, name:%s", g_notice_msg.file_type, g_notice_msg.file_name);
	if(g_file_trans.file_buffer!=NULL) free(g_file_trans.file_buffer);
	g_file_trans.file_buffer = NULL;
	memset(&g_file_trans,0,sizeof(g_file_trans));
}

static cJSON *make_dev_info(cJSON *pJsRoot) //打包设备信息到JSON
{
	if(!pJsRoot) pJsRoot =cJSON_CreateObject();
	g_flash_sn = file_addr_init("bksn",FILE_BL_BKSN_ADDR, FILE_BL_BKSN_SIZE);
	g_flash_sn->buff =(char *)malloc(sizeof(uint8_t)*g_flash_sn->size);
	read_data_from_file(g_flash_sn);
    g_flash_dev =file_addr_init("dev",FILE_BL_DEV_ADDR,FILE_BL_DEV_SIZE);
    g_flash_dev->buff =(char *)malloc(sizeof(uint8_t)*g_flash_dev->size);
    read_data_from_file(g_flash_dev);
    cJSON *devdata =cJSON_Parse(g_flash_dev->buff);
    char *devNamedata =(devdata?GET_JSON_ITEM(devdata,"dn",valuestring,""):"");
	char *devManudata =(devdata?GET_JSON_ITEM(devdata,"mn",valuestring,""):"");
	char *devDescdata =(devdata?GET_JSON_ITEM(devdata,"dd",valuestring,""):"");
	if(devdata) cJSON_Delete(devdata);
	cJSON *tempJson =cJSON_CreateObject();
	cJSON_AddStringToObject(tempJson,"sn",g_flash_sn->buff);
	cJSON_AddStringToObject(tempJson,"model","VAV-10");
	cJSON_AddStringToObject(tempJson,"type","VAV");
	cJSON_AddStringToObject(tempJson,"name",devNamedata);
	cJSON_AddStringToObject(tempJson,"mn",devManudata);
	cJSON_AddStringToObject(tempJson,"desc",devDescdata);
	cJSON *devinfo =cJSON_CreateArray();
	cJSON_AddItemToArray(devinfo,tempJson);
	cJSON_AddItemToObject(pJsRoot,"devinfo",devinfo);
	free_w25flash_t(&g_flash_sn);
	free_w25flash_t(&g_flash_dev);
	return pJsRoot;
}

static int change_dev_info(cJSON *pJsRoot) //从JSON修改设备信息
{
    g_flash_dev =file_addr_init("dev",FILE_BL_DEV_ADDR,FILE_BL_DEV_SIZE);
    g_flash_dev->buff =(char *)malloc(sizeof(uint8_t)*g_flash_dev->size);
    read_data_from_file(g_flash_dev);
    cJSON *devdata =cJSON_Parse(g_flash_dev->buff);
	if(!devdata) devdata =cJSON_CreateObject();
	cJSON *pJsSetName =cJSON_GetObjectItem(pJsRoot,"name");
	cJSON *pJsSetDesc =cJSON_GetObjectItem(pJsRoot,"desc");
	if(pJsSetName) {
		cJSON_DeleteItemFromObject(devdata,"dn");
		cJSON_AddStringToObject(devdata,"dn",pJsSetName->valuestring?pJsSetName->valuestring:"");
	}
	if(pJsSetDesc) {
		cJSON_DeleteItemFromObject(devdata,"dd");
		cJSON_AddStringToObject(devdata,"dd",pJsSetDesc->valuestring?pJsSetDesc->valuestring:"");
	}
	char *newdevdata = cJSON_PrintUnformatted(devdata);
	strcpy(g_flash_dev->buff,newdevdata);
	omip_free(newdevdata);
	OMIP_LOG_INFO( "set devinfo(%d):%s\r\n", g_flash_dev->size,(char *)(g_flash_dev->buff));
	save_data_to_file(g_flash_dev);
	free_w25flash_t(&g_flash_dev);
	return 0;
}

static void cengine_parse_status_callback(int param)
{
    omip_printf(OMIP_INFO, "set led %s\r\n", param == 1 ? "green" : "red");
	vav_set_sys_status_led(param);
}

static int synchronize_time_request(void)
{
	OMIP_LOG_INFO( "synchronize time request\r\n");
    int ret = omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_SYN_TIME, (unsigned char *)"NULL", strlen("NULL"));
    if(ret !=OMIP_OK) {
		omip_printf(OMIP_ERROR_UPLOAD, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
    }
    return ret;
}

static int synchronize_time_response(unsigned long long sec)
{
    mcu_tm tm;
	mcu_set_time_by_sec(sec);
	offset_time(sec,(60*60)*8,&tm); //timezone beijing +8h
    OMIP_LOG_ERROR("synchronized datetime: %d-%02d-%02d %02d:%02d:%02d\r\n", tm.tm_year,tm.tm_mon,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec);
    return 0;
}

void mcu_del_virtualDev()
{
    cJSON *root = cJSON_CreateObject();
    cJSON *item_devinfo = cJSON_CreateObject();
    cJSON *item_virtualinfo = cJSON_CreateObject();
	cJSON *virtualDevArray = cJSON_CreateArray(); 
    g_flash_sn = file_addr_init("bksn",FILE_BL_BKSN_ADDR, FILE_BL_BKSN_SIZE);
    g_flash_sn->buff = malloc(sizeof(uint8_t)*g_flash_sn->size);
    read_data_from_file(g_flash_sn);
    if(g_flash_sn->buff!=NULL) cJSON_AddStringToObject(item_devinfo,"sn",g_flash_sn->buff);
    else					   omip_printf(OMIP_INFO,"bl_data_sn.txt not exist.\r\n");
    cJSON_AddStringToObject(item_devinfo, "model", "VAV10");
    cJSON_AddStringToObject(item_devinfo, "manu", "1003");
    cJSON_AddStringToObject(item_devinfo, "name", "VAV10 BOX");
    cJSON_AddStringToObject(item_devinfo, "mac", "");
    cJSON_AddStringToObject(item_devinfo, "hiv", "");
    cJSON_AddStringToObject(item_devinfo, "fwv", g_mcu_version);
    cJSON_AddStringToObject(item_devinfo, "hwv", "VER.C");
    cJSON_AddStringToObject(item_devinfo, "swv", "V100R001C01B010");
    cJSON_AddStringToObject(item_devinfo, "status", "1");
    if(strcmp((char*)g_hlink_info.fwv,"WiFi.ailian")==0)		cJSON_AddStringToObject(item_devinfo,"protType","WiFi");
    else if(strcmp((char*)g_hlink_info.fwv,"PLC.huawei")==0)	cJSON_AddStringToObject(item_devinfo,"protType","PLC");
    else														cJSON_AddStringToObject(item_devinfo,"protType","ETH");
    cJSON_AddItemToObject(root,"devInfo",item_devinfo);
    g_flash_dev = file_addr_init("dev",FILE_BL_DEV_ADDR,FILE_BL_DEV_SIZE);
    g_flash_dev->buff = malloc(sizeof(uint8_t)*g_flash_dev->size);
    read_data_from_file(g_flash_dev);
    cJSON *devdata =cJSON_Parse(g_flash_dev->buff);
    if (devdata != NULL) {
        char *devTypedata = GET_JSON_ITEM(devdata, "dt", valuestring, "");
        char *devNamedata = GET_JSON_ITEM(devdata, "dn", valuestring, "");
        char *devModeldata = GET_JSON_ITEM(devdata, "dm", valuestring, "");
        char *devManudata = GET_JSON_ITEM(devdata, "mn", valuestring, "");
		char *devDescdata = GET_JSON_ITEM(devdata, "dd", valuestring, "");
        cJSON_AddStringToObject(item_virtualinfo, "model", devModeldata);
        cJSON_AddStringToObject(item_virtualinfo, "manu", devManudata);
        cJSON_AddStringToObject(item_virtualinfo, "name", devNamedata);
        cJSON_AddStringToObject(item_virtualinfo, "devType", devTypedata);
        cJSON_AddStringToObject(item_virtualinfo, "desc", devDescdata);
        cJSON_AddStringToObject(item_virtualinfo, "operate", "delete");
    }
	else {omip_printf(OMIP_INFO,"[%s:%d]virtual device not exist.\r\n",__FUNCTION__,__LINE__);}
	if(devdata) cJSON_Delete(devdata);
    cJSON_AddItemToArray(virtualDevArray, item_virtualinfo);
    cJSON_AddItemToObject(root,"virtualDevInfo",virtualDevArray);
    char *update_char =cJSON_PrintUnformatted(root);
    omip_printf(OMIP_ERROR,"this is update_info_json:%s\r\n",update_char);
    if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_JSON,HLINK_CMD_DEV_INFO_UPDATE,(uint8_t *)update_char,strlen(update_char)+1) !=OMIP_OK)
        omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
    memset(g_flash_dev->buff,0,g_flash_dev->size);
    save_data_to_file(g_flash_dev); //保存设备信息到flash
    omip_free(update_char);
    cJSON_Delete(root);
	free_w25flash_t(&g_flash_dev);
    free_w25flash_t(&g_flash_sn);
}

static int device_manager_set_loglevel_mcu_proc(char* level)
{
	omip_log_level log_level = OMIP_EMGENCY;

	if (level == NULL) {
		return -1;
	}
	int ret = hlink_log_get_level_by_string(level, &log_level);

    if (ret != 0) {
        omip_printf(OMIP_ERROR_UPLOAD, "get log level by string failed!\n", log_level);
        return -1;
    }

    hlink_log_level_set(log_level);
    MCU_LOG(MCU_LOG_INFO_UPLOAD, "set mcu loglevel to %s success!", level);
    return 0;

}

static void device_manger_json(uint8_t ct, uint8_t* data, int len)
{
	int ret = -1;

	if (data == NULL) {
		omip_printf(OMIP_ERROR_UPLOAD,"received data is NULL\n");
		return;
	}
	cJSON *device_manager_info = cJSON_Parse((char*) data);
	if(device_manager_info == NULL) {
		omip_printf(OMIP_ERROR_UPLOAD,"cjson parse data failed\n");
		return;
	}

	char *operateCode = GET_JSON_ITEM(device_manager_info, "operateCode", valuestring, "");
	if (strcmp(operateCode, "log-level") == 0) {
		char *level = GET_JSON_ITEM(device_manager_info, "level", valuestring, "");
		device_manager_rsp device_mngr_rsp = { 0, 0, {0} };
		device_mngr_rsp.message_id = GET_JSON_ITEM(device_manager_info, "mid", valueint, -1);
		//设置mcu日志级别
		ret = device_manager_set_loglevel_mcu_proc(level);
		if (ret != 0) {
			device_mngr_rsp.errcode = HLINK_ERR_INVALID_PARA;
		}
		if (omip_api_send(OMIP_VC_DEFAULT0, ct, HLINK_CMD_DEVICE_MANAGER_RSP, (uint8_t*) &device_mngr_rsp, sizeof(device_mngr_rsp)) != OMIP_OK) {
			omip_printf(OMIP_ERROR_UPLOAD, "====omip_api_send HLINK_CMD_DEVICE_MANAGER_RSP failed!\n");
		}
	} else {
		omip_printf(OMIP_ERROR_UPLOAD,"cmd is not support\n");
	}

	cJSON_Delete(device_manager_info);
}


static void device_manger_binary(uint8_t ct, uint8_t* data, int len)
{
    omip_printf(OMIP_ERROR,"get device manager cmd :%s\r\n",data);
    device_manager_rsp device_mngr_rsp = { 0, 0, {0} };
    if(OMIP_CONTENT_FORMAT_BINARY != ct)
    {
        omip_printf(OMIP_INFO,"sys command,current hlink version only support ct[%d]\r\n",OMIP_CONTENT_FORMAT_BINARY);
        device_mngr_rsp.errcode = HLINK_ERR_INVALID_FORMAT;
        char *errDesc = "ct is not OMIP_CONTENT_FORMAT_BINARY";
        (void) memcpy_s(device_mngr_rsp.errDesc, HLINK_DESC_LEN_MAX, errDesc, strlen(errDesc));
        if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_DEVICE_MANAGER_RSP, (uint8_t*) &device_mngr_rsp, sizeof(device_mngr_rsp)) != OMIP_OK) //received online from hlink module, send dev_reg to hlink module
            omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
        return;
    }
    if(len != sizeof(device_manager))
    {
        omip_printf(OMIP_INFO,"device_manager length is wrong,len [%d] expect len[%d]!\r\n", len, sizeof(device_manager));
        device_mngr_rsp.errcode = HLINK_ERR_INVALID_PARA;
        if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_DEVICE_MANAGER_RSP, (uint8_t*) &device_mngr_rsp, sizeof(device_mngr_rsp)) != OMIP_OK) //received online from hlink module, send dev_reg to hlink module
            omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
        return;
    }
    device_manager *device_mngr = (device_manager *)data;
    omip_printf(OMIP_INFO, "device_mngr operate_code %s\r\n", device_mngr->operate_code);
    device_mngr_rsp.message_id = device_mngr->message_id;
    if(strcmp(device_mngr->operate_code, "reboot") == 0)
    {
        device_mngr_rsp.errcode = HLINK_OK;
        if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_DEVICE_MANAGER_RSP, (uint8_t*) &device_mngr_rsp, sizeof(device_mngr_rsp)) != OMIP_OK) //received online from hlink module, send dev_reg to hlink module
            omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
    }
    else if(strcmp(device_mngr->operate_code, "deleteVirtualDevice") == 0)
    {
        printf("delete local virtual device\r\n");
        device_mngr_rsp.errcode = HLINK_OK;
        if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_DEVICE_MANAGER_RSP, (uint8_t*) &device_mngr_rsp, sizeof(device_mngr_rsp)) != OMIP_OK) //received online from hlink module, send dev_reg to hlink module
            omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
        omip_printf(OMIP_INFO, "device_mngr device_name %s\n", device_mngr->device_name);
        mcu_del_virtualDev();
        omip_printf(OMIP_ERROR,"delete local virtual device succ.\r\n");
    }
	else if (strcmp(device_mngr->operate_code, "upload_log") == 0) {
		device_mngr_rsp.errcode = HLINK_OK;
		if (omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_DEVICE_MANAGER_RSP, (uint8_t*) &device_mngr_rsp, sizeof(device_mngr_rsp)) != OMIP_OK) //received online from hlink module, send dev_reg to hlink module
		{
			omip_printf(OMIP_ERROR_UPLOAD, "====omip_api_send HLINK_CMD_DEVICE_MANAGER_RSP failed!\r\n");
		}
		device_manager_logfile_mcu_task_create(MCU_UPLOAD_LOGFILE_GW);
	}
    else
    {
        device_mngr_rsp.errcode = HLINK_ERR_INVALID_PARA;
        if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_DEVICE_MANAGER_RSP, (uint8_t*) &device_mngr_rsp, sizeof(device_mngr_rsp)) != OMIP_OK) //received online from hlink module, send dev_reg to hlink module
            omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
    }
    return;
}

//#define MYDEBUG
#define LITE
void mcu_start_local_flow()
{
#ifdef LITE
    int flag =0x00, length =0x00;
    W25QXX_Read((uint8_t *)&flag,0x100400,2);
    OMIP_LOG_INFO("=================local flag: %x=================", flag);
    W25QXX_Read((uint8_t *)&length,0x100402,4);
#endif
	static uint8_t bFirst =1;
	uint32_t curTime =0, lstTime =0;
	if(bFirst)
	{
		lstTime =LOS_Tick2MS(LOS_TickCountGet());
		curTime =lstTime;
		OMIP_LOG_INFO("wait valve calibrate...");
#ifndef MYDEBUG
		while(!vav_read_valve_cali_status())
		{
			curTime =LOS_Tick2MS(LOS_TickCountGet());
			osal_task_sleep(500);
			if(abs(curTime-lstTime) >180000) {omip_printf(OMIP_ERROR,"[%s:%d]calibrate timeout.\r\n",__FUNCTION__,__LINE__); break;}
		}
#endif
		OMIP_LOG_INFO("Valve finished calibrate, start up cengine\r\n");
#ifdef LITE
		cengine_register_parse_status_callback(cengine_parse_status_callback);
		cengine_register_all_nodes();
#endif
		bFirst = 0;
	}
#ifdef LITE
    if(flag !=0x77 ||length<=0) {omip_printf(OMIP_ERROR,"[%s:%d]no local flow.(flag:0x%x,length:%d)\r\n",__FUNCTION__,__LINE__,flag,length); return;}
    w25flash_t *flow_local_data =file_addr_init("flow_local_data",FILE_FLOW_ADDR,length);
    flow_local_data->buff = malloc(sizeof(uint8_t)*flow_local_data->size);
    read_data_from_file(flow_local_data);
    //printf("%c %c %s\r\n",flow_local_data->buff[0],flow_local_data->buff[1],flow_local_data->buff);
    cengine_parse_metadata(flow_local_data->buff,strlen(flow_local_data->buff));
    cengine_process_init();
	free_w25flash_t(&flow_local_data);
    OMIP_LOG_INFO("Local flow start success!\r\n");
#endif
}

void send_dev_update_req_json()
{
    cJSON *root =cJSON_CreateObject();
    cJSON *item_devinfo = cJSON_CreateObject();
    g_flash_sn = file_addr_init("bksn",FILE_BL_BKSN_ADDR, FILE_BL_BKSN_SIZE);
    g_flash_sn->buff = malloc(sizeof(uint8_t)*g_flash_sn->size);
    read_data_from_file(g_flash_sn);
	
    if(g_flash_sn->buff!=NULL)	cJSON_AddStringToObject(item_devinfo,"sn",g_flash_sn->buff);
	else						omip_printf(OMIP_INFO,"bl_data_sn.txt not exist.\r\n");
    cJSON_AddStringToObject(item_devinfo, "model", "VAV10");
    cJSON_AddStringToObject(item_devinfo, "manu", "1003");
    cJSON_AddStringToObject(item_devinfo, "name", "VAV10 BOX");
    cJSON_AddStringToObject(item_devinfo, "mac", "");
    cJSON_AddStringToObject(item_devinfo, "hiv", "");
    cJSON_AddStringToObject(item_devinfo, "fwv", g_mcu_version);
    cJSON_AddStringToObject(item_devinfo, "hwv", "VER.C");
    cJSON_AddStringToObject(item_devinfo, "swv", "V100R001C01B010");
    cJSON_AddStringToObject(item_devinfo, "status", "1");
    if(strcmp((char*)g_hlink_info.fwv,"WiFi.ailian")==0) 	  cJSON_AddStringToObject(item_devinfo,"protType","WiFi");
    else if(strcmp((char*)g_hlink_info.fwv,"PLC.huawei")==0)  cJSON_AddStringToObject(item_devinfo,"protType","PLC");
    else													  cJSON_AddStringToObject(item_devinfo, "protType", "ETH");
    cJSON_AddItemToObject(root, "devInfo", item_devinfo);
    g_flash_dev =file_addr_init("dev",FILE_BL_DEV_ADDR,FILE_BL_DEV_SIZE);
    g_flash_dev->buff = (char *)malloc(sizeof(uint8_t)*g_flash_dev->size);
    read_data_from_file(g_flash_dev);
    if(g_flash_dev->buff !=NULL)
	{
        cJSON *devdata =cJSON_Parse(g_flash_dev->buff);
        if(NULL !=devdata){
			cJSON *virtualDevArray =cJSON_CreateArray();    
        	cJSON *item_virtualinfo =cJSON_CreateObject();
            char *devTypedata = GET_JSON_ITEM(devdata, "dt", valuestring, "");
            char *devNamedata = GET_JSON_ITEM(devdata, "dn", valuestring, "");
            char *devModeldata = GET_JSON_ITEM(devdata, "dm", valuestring, "");
			char *devManudata = GET_JSON_ITEM(devdata, "mn", valuestring, "");
			char *devDescdata = GET_JSON_ITEM(devdata, "dd", valuestring, "");
            cJSON_AddStringToObject(item_virtualinfo, "model", devModeldata);
            cJSON_AddStringToObject(item_virtualinfo, "manu", devManudata);
            cJSON_AddStringToObject(item_virtualinfo, "name", devNamedata);
            cJSON_AddStringToObject(item_virtualinfo, "devType", devTypedata);
            cJSON_AddStringToObject(item_virtualinfo, "desc", devDescdata);
            cJSON_AddItemToArray(virtualDevArray, item_virtualinfo);
            cJSON_AddItemToObject(root, "virtualDevInfo", virtualDevArray);
        }
		else {omip_printf(OMIP_INFO,"bl_data_dev.txt not exist\r\n");}
		if(devdata)	cJSON_Delete(devdata);
    }
    char *update_char =cJSON_PrintUnformatted(root);
    OMIP_LOG_INFO("update info json:%s\r\n", update_char);
    if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_JSON,HLINK_CMD_DEV_INFO_UPDATE,
					(uint8_t *)update_char,strlen(update_char)+1) != OMIP_OK){
        OMIP_LOG_ERROR("omip_api_send failed!\r\n");
	}
    omip_free(update_char);
	free_w25flash_t(&g_flash_dev);
    free_w25flash_t(&g_flash_sn);
}

void send_update_bin_info()
{
    int flag = 0x00;
    W25QXX_Read((uint8_t *)&flag,FILE_BIN_UPDATE_FLAG_ADDR,FILE_FLAG_LENGTH);
    if(flag != 0x77) {
		OMIP_LOG_INFO("just common restart,no need to send update info.\r\n"); 
		return;
	}
    OMIP_LOG_INFO("bin has updated,now send update info.\r\n");
    send_dev_update_req_json();
    int erase_bin_update_flag = 0x00;
    W25QXX_Write((uint8_t *)&erase_bin_update_flag, FILE_BIN_UPDATE_FLAG_ADDR , FILE_FLAG_LENGTH);
    led_wifi_on();
}

void mcu_stop_local_flow()
{
    int flag =0x00, length =0x00;
    W25QXX_Read((uint8_t *)&flag,0x100400,2);
    omip_printf(OMIP_ERROR,"[%s:%d]=================local flag: %x=================\r\n",__FUNCTION__,__LINE__,flag);
    W25QXX_Read((uint8_t *)&length,0x100402,4);
    if(flag!=0x77 ||length<=0) {omip_printf(OMIP_ERROR,"[%s:%d]no local flow.(flag:0x%x,length:%d)\r\n",__FUNCTION__,__LINE__,flag,length); return;}
    cengine_free_last_flow_resource();
    cengine_init_flow_all_nodes();
    omip_printf(OMIP_ERROR,"[%s:%d]local flow start success!\r\n",__FUNCTION__,__LINE__);
}

void mcu_only_stop_local_flow()
{
    cengine_free_last_flow_resource();
    cengine_init_flow_all_nodes();
}

void mcu_only_start_local_flow()
{
    int length = 0x00;
    W25QXX_Read((uint8_t *)&length,0x100402,4);
    w25flash_t *flow_local_data = file_addr_init("flow_local_data",FILE_FLOW_ADDR,length);
    flow_local_data->buff =(char *)malloc(sizeof(uint8_t)*flow_local_data->size);
    read_data_from_file(flow_local_data);
    cengine_parse_metadata(flow_local_data->buff,strlen(flow_local_data->buff));
    cengine_process_init();
	free_w25flash_t(&flow_local_data);
}

static void send_file_mngr_result(int errCode) //HLINK发送文件传输完成通知
{
    file_mngr_result result_msg = {0};
    char *err_desc ="file transfer is error", *succ_desc="file transfer is success";
    memcpy_s(result_msg.file_name,HLINK_FILE_NAME_LEN_MAX,g_notice_msg.file_name,strlen((char*)g_notice_msg.file_name));
    memcpy_s(result_msg.file_type,HLINK_FILE_TYPE_LEN_MAX,g_notice_msg.file_type,strlen((char*)g_notice_msg.file_type));
    memcpy_s(result_msg.file_version,HLINK_FILE_VERSION_LEN_MAX,g_notice_msg.file_version,strlen((char*)g_notice_msg.file_version));
	if(errCode ==OMIP_FILE_OK) {
		result_msg.errcode =(g_file_trans.received_size!=g_file_trans.notice_size? OMIP_FILE_SIZE_ERROR : OMIP_FILE_OK);
	}
	else {
		result_msg.errcode = errCode;
	}
    strcpy(result_msg.err_desc,(result_msg.errcode==OMIP_FILE_OK? succ_desc : err_desc));
    result_msg.file_size =g_file_trans.received_size;
    OMIP_LOG_INFO("file result.file_size:%ld,received_size:%ld,errcode:%d\r\n", g_file_trans.notice_size,g_file_trans.received_size,result_msg.errcode);
	int ret = omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_BINARY,HLINK_CMD_FILE_MNGR_RESULT,(uint8_t*)&result_msg,sizeof(result_msg));
	if(ret !=OMIP_OK) {//received black end send result
        OMIP_LOG_ERROR("omip_api_send failed!\r\n");
	}
}

static void send_ble_file_mngr_result(int errCode, char *status) //蓝牙发送文件传输完成通知
{
	int iErrCode =errCode;

	cJSON *pJsRespond =cJSON_CreateObject();
	cJSON_AddItemToObject(pJsRespond,"mid",cJSON_CreateNumber(g_file_trans.notice_mid));
	cJSON_AddItemToObject(pJsRespond,"errcode", cJSON_CreateNumber(iErrCode));
	cJSON_AddItemToObject(pJsRespond,"status",cJSON_CreateString(status));


	cJSON *para_json =cJSON_CreateObject();
	cJSON_AddItemToObject(pJsRespond,"paras",para_json);
	cJSON_AddStringToObject(para_json,"fileName",(char *)(g_notice_msg.file_name));
	//cJSON_AddStringToObject(para_json,"fileType",(char *)(g_notice_msg.file_type));
	mcu_send_json_ble(HLINK_CMD_FILE_MNGR_RESULT,pJsRespond,1); //向蓝牙HLINK发送JSON数据
}

typedef struct _ble_fw_update //蓝牙固件更新信息
{
	char	from_app; 		//是否是从APP来的包
	int 	pack_offset;	//固件在包中的偏移
	int 	fw_len;			//固件长度
	char   filename[LOAD_BIN_SUBFILENAME_LEN+1];
}ble_fw_update;

void mcu_ble_firmware_process(void* args) //处理蓝牙固件更新线程
{
	ble_fw_update *pst_ble_fw =(ble_fw_update *)args;
    int pro_ret =HLINK_ERR_COMMON_ERROR;
    int upgrade_state = 0;
    unsigned char ble_file_data[96] ={0};
	int schedule_print = 0;
    ble_file_data[0] =(pst_ble_fw->fw_len >> 24) & 0xff;
    ble_file_data[1] =(pst_ble_fw->fw_len >> 16) & 0xff;
    ble_file_data[2] =(pst_ble_fw->fw_len >> 8) & 0xff;
    ble_file_data[3] =(pst_ble_fw->fw_len & 0xff);
	
	if(pst_ble_fw->from_app ==0) {//是从网关来的包,使用现有的SHA256
		memcpy_s(ble_file_data+4,HLINK_FILE_CHECK_SUM_LEN_MAX,g_file_trans.checksum,HLINK_FILE_CHECK_SUM_LEN_MAX);
	}
	else { //是从APP来的包,计算SHA256
		get_sha256((unsigned char *)(g_file_trans.file_buffer+pst_ble_fw->pack_offset),pst_ble_fw->fw_len,(char *)(ble_file_data+4));
	}
	
    if(OSAL_OK != osal_semp_create(&Mutex_ble_handle,1024,0)) {
		omip_printf(OMIP_ERROR,"[%s:%d]create ble semp failed!\r\n",__FUNCTION__,__LINE__);
		goto send_result;
	}
	
    for(int send_notify_times=0; send_notify_times<3; send_notify_times++) //发送三次通知等待蓝牙应答
    {
		OMIP_LOG_INFO("send ble file mngr notice");
        mcu_general_send_ble(HLINK_CMD_BLE_FILE_MNGR_NOTICE, OMIP_CONTENT_FORMAT_BINARY, ble_file_data, 4+HLINK_FILE_CHECK_SUM_LEN_MAX);
        pro_ret = osal_semp_pend(Mutex_ble_handle,3000);
		
        if(pro_ret==OSAL_OK && g_file_trans.ble_ota_res==1) {
			upgrade_state = 1; 
			break;
		}
    }
	
	if(upgrade_state != 1)	{
		print_debug(0, "pend Mutex_ble_handle timeout");
		print_debug(0, "ack pro_ret:%d, ble_ota_res:%d", pro_ret, g_file_trans.ble_ota_res);
		goto del_mutex;
	}
	
    int send_file_size =0, retry_times =0; //已发送长度、重试次数
    omip_printf(OMIP_INFO,"start to send file block to ble module,timeout=%d.\r\n",g_file_trans.ble_ota_tmout);
	osal_task_sleep(g_file_trans.ble_ota_tmout);
    while(send_file_size <pst_ble_fw->fw_len)
    {
    	unsigned char *data_send =(unsigned char *)(g_file_trans.file_buffer + pst_ble_fw->pack_offset + send_file_size);
    	int sendlen =(pst_ble_fw->fw_len-send_file_size>=100)? 100 : (pst_ble_fw->fw_len-send_file_size);
		mcu_general_send_ble(HLINK_CMD_BLE_FILE_MNGR_BLOCK,OMIP_CONTENT_FORMAT_BINARY,data_send,sendlen); //向蓝牙发送固件
        if(OSAL_OK == osal_semp_pend(Mutex_ble_handle,3000)) //超时时间 3s
        {
            omip_printf(OMIP_DEBUG,"ble block rsp=%d timeout=%d ms\r\n",g_file_trans.ble_ota_res,g_file_trans.ble_ota_tmout);
            osal_task_sleep(g_file_trans.ble_ota_tmout);
            if(g_file_trans.ble_ota_res == 1)
            {
                send_file_size += sendlen;
                retry_times =0;
            }
            else if (++retry_times >10)
			{
            	omip_printf(OMIP_ERROR, "[%s:%d]send ble file block failed!\r\n",__FUNCTION__,__LINE__);
                pro_ret =HLINK_ERR_COMMON_ERROR;
				goto del_mutex;
			}
        }
        else
        {
        	pro_ret =HLINK_ERR_COMMON_ERROR;
        	omip_printf(OMIP_ERROR,"[%s:%d]wait Mutex_ble_handle timeout while sending ble block!\r\n",__FUNCTION__,__LINE__);
            goto del_mutex;
        }
		
		int schedule = (send_file_size * 100) / pst_ble_fw->fw_len;
		if((schedule > schedule_print) && (0 == schedule%10)) {
			OMIP_LOG_INFO( "send ble file completion :%d%%",  schedule);
			schedule_print = schedule;
		}		
    }
	//mcu_general_send_ble(HLINK_CMD_BLE_FILE_MNGR_BLOCK_END,OMIP_CONTENT_FORMAT_BINARY,ble_file_data,4);
	pro_ret = HLINK_OK;
	
	OMIP_LOG_INFO("send ble file end");
	mcu_general_send_ble(HLINK_CMD_BLE_FILE_MNGR_BLOCK_END,OMIP_CONTENT_FORMAT_BINARY,ble_file_data,4);
del_mutex:
	//send_ble_file_mngr_end(pro_ret, pst_ble_fw->filename);

send_result:
	if(pst_ble_fw != NULL) {
		free(pst_ble_fw); //释放参数结构体
		pst_ble_fw = NULL;
	}
	if(g_file_trans.ble_ota_taskid != NULL) {
		free_file_buff();
	}
	//free_ble_update_task(); //如果是开的线程则释放线程ID
}

int mcu_blefw_update_task(        char from_app,int pack_offset,int fw_len,   char *filename, char sync_exe) //蓝牙固件升级任务
{
	ble_fw_update *pst_ble_fw =(ble_fw_update *)malloc(sizeof(ble_fw_update));
	memset_s(pst_ble_fw, sizeof(pst_ble_fw), 0, sizeof(pst_ble_fw));
	pst_ble_fw->from_app =from_app;
	pst_ble_fw->pack_offset = pack_offset;
	pst_ble_fw->fw_len = fw_len;
	strcpy_s(pst_ble_fw->filename, LOAD_BIN_SUBFILENAME_LEN, filename);
	osal_task_sleep(100);
	if(sync_exe ==1) //同步执行
	{
		OMIP_LOG_INFO("package Synchronize update start!\r\n");
		g_file_trans.ble_ota_taskid =NULL;
		mcu_ble_firmware_process((void *)pst_ble_fw);
	}
	else //异步执行,开线程
	{
	    OMIP_LOG_INFO("package asynchronous update start!\r\n");
	    g_file_trans.ble_ota_taskid =osal_task_create("ble_firmware_update",(int (*)(void *))mcu_ble_firmware_process,(void *)pst_ble_fw,1024*2,NULL,23);
	    if(g_file_trans.ble_ota_taskid==NULL) {omip_printf(OMIP_ERROR,"[%s:%d]task create failed!\r\n",__FUNCTION__,__LINE__); return -1;}
	}
	return 0;
}

static int send_hlink_file_notice(BIN_SUBFILE_HEAD_S *subfile_header, SEFS *tail_info, int mid)
{
	
	/* prepare file notice json*/
	cJSON *root = NULL;
	cJSON *para_json = NULL;
	char* notice_info;

	para_json = cJSON_CreateObject();
	if (para_json == NULL) {
		omip_printf(OMIP_ERROR, "json create object failed\n");
		return HLINK_ERR_COMMON_ERROR;
	}
	
    cJSON_AddStringToObject(para_json, "operateCode", "download");
    cJSON_AddStringToObject(para_json, "fileName", (const char * const)(subfile_header->sub_file_name));
    cJSON_AddStringToObject(para_json, "fileType", "hlink_firmware");
    cJSON_AddNumberToObject(para_json, "fileSize", tail_info->code_len);
    cJSON_AddStringToObject(para_json, "fileVersion", (const char * const)(tail_info->product_version));
    char checksum[HLINK_FILE_CHECK_SUM_LEN_MAX+1];
    if(memcpy_s(checksum, HLINK_FILE_CHECK_SUM_LEN_MAX, tail_info->checksum, HLINK_FILE_CHECK_SUM_LEN_MAX) != EOK)
    {
        omip_printf(OMIP_ERROR, "memcpy checksum1 failed!\r\n");
        cJSON_Delete(para_json);
        return HLINK_ERR_COMMON_ERROR;
    }
    checksum[HLINK_FILE_CHECK_SUM_LEN_MAX] = '\0';
    cJSON_AddStringToObject(para_json, "checkSum", (const char *const)(checksum));

	root = cJSON_CreateObject();
    if (root == NULL) {
        cJSON_Delete(para_json);
        omip_printf(OMIP_ERROR, "json create object failed\n");
        return HLINK_ERR_COMMON_ERROR;
    }
    cJSON_AddStringToObject(root, "srv", "set");
    cJSON_AddStringToObject(root, "cmd", "file");
    cJSON_AddNumberToObject(root, "mid", mid);
    cJSON_AddItemToObject(root, "paras", para_json);
    notice_info = cJSON_PrintUnformatted(root);
    if (notice_info == NULL) {
        cJSON_Delete(root);
        return HLINK_ERR_COMMON_ERROR;
    }

    /* send file notice */
    omip_printf(OMIP_INFO, "start to send notice to hlink: %s\n", notice_info);
    if (omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_JSON, HLINK_CMD_FILE_MNGR_NOTICE,
        (unsigned char *)notice_info, strlen(notice_info)+1) != OMIP_OK) {
        omip_free(notice_info);
        omip_printf(OMIP_ERROR, "send HLINK_CMD_FILE_MNGR_NOTICE to module failed\n");
        return HLINK_ERR_COMMON_ERROR;
    }

	cJSON_Delete(root);
	omip_free(notice_info);
	osal_task_sleep(1000*20); /* hlink will erase flash after recv notice, wait hlink erase flash */
	return HLINK_OK;
}

static int send_hlink_file_block_end(void)
{
    cJSON* paras = NULL;
    cJSON* root = NULL;
    char* file_block_end;

    paras = cJSON_CreateObject();
    if (paras == NULL) {
        omip_printf(OMIP_ERROR, "create paras failed\n");
        return HLINK_ERR_COMMON_ERROR;
    }
    cJSON_AddStringToObject(paras, "fileName", "package v2.1.0");

    root = cJSON_CreateObject();
    if (root == NULL) {
        cJSON_Delete(paras);
        omip_printf(OMIP_ERROR, "create root failed\n");
        return HLINK_ERR_COMMON_ERROR;
    }
    cJSON_AddStringToObject(root, "srv", "set");
    cJSON_AddStringToObject(root, "cmd", "file");
    cJSON_AddNumberToObject(root, "mid", 2);
    cJSON_AddItemToObject(root, "paras", paras);

    file_block_end = cJSON_PrintUnformatted(root);
    if (file_block_end == NULL) {
        cJSON_Delete(root);
        omip_printf(OMIP_ERROR, "create file_block_end failed\n");
        return HLINK_ERR_COMMON_ERROR;
    }
    omip_printf(OMIP_INFO, "HLINK file_block_end: %s\r\n", file_block_end);

    /* send file block end to hlink module */
    if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_FILE_MNGR_BLOCK_END,
        (unsigned char *)file_block_end, strlen(file_block_end)+1) != OMIP_OK) {
        omip_printf(OMIP_ERROR, "send HLINK_CMD_FILE_MNGR_BLOCK_END to hlink failed\n");
        cJSON_Delete(root);
        osal_free(file_block_end);
        return HLINK_ERR_COMMON_ERROR;
    }

    cJSON_Delete(root);
    osal_free(file_block_end);
    return HLINK_OK;
}

static int get_file_rsp_errcode(const char* data)
{
	cJSON *file_rsp = cJSON_Parse((char*) data);
	int errcode;
	if (file_rsp == NULL) {
		omip_printf(OMIP_ERROR, "parse failed\n");
		return -1;
	}
	if (data == NULL) {
		omip_printf(OMIP_ERROR, "data is NULL\n");
		return -1;
	}

    errcode = GET_JSON_ITEM(file_rsp, "errcode", valueint, -1);
    cJSON_Delete(file_rsp);
    return errcode;
}

void set_hlink_upgrade_result(int upgrade_result)
{
    g_hlink_upgrade_result = upgrade_result;
    osal_semp_post(g_hlink_ota_semp);
}

static int get_hlink_upgrade_result(void)
{
    int ret;
    g_hlink_upgrade_result = PACKAGE_INVALIDE_ERRCODE;
    ret = osal_semp_pend(g_hlink_ota_semp, 1000*300); // wait 5 mins
    if(ret != OSAL_OK) {
        OMIP_LOG_ERROR("pend g_hlink_ota_semp semp failed or timeout\n");
    }

    osal_semp_del(g_hlink_ota_semp);
    return g_hlink_upgrade_result;
}

static int upgrade_hlink_firmware(BIN_SUBFILE_HEAD_S *subfile_header, SEFS *tail_info, int mid)
{
	int ret = 0;
	int schedule_print = 0;
    if(osal_semp_create(&g_hlink_ota_semp, 1024, 0) != OSAL_OK) {
	    OMIP_LOG_ERROR("create g_hlink_ota_semp semp failed\n");
	    return HLINK_ERR_COMMON_ERROR;
    }

	/* 1. send file notice, json */
    ret = send_hlink_file_notice(subfile_header, tail_info, mid);
    if (ret != HLINK_OK) {
        osal_semp_del(g_hlink_ota_semp);
        return HLINK_ERR_COMMON_ERROR;
    }

    /* 2. send file block */
    int send_file_size =0; 
    OMIP_LOG_INFO( "start to send HLINK_CMD_FILE_MNGR_BLOCK to hlink, firmware_size = %d\n", tail_info->code_len);
    while (send_file_size < tail_info->code_len) {

		/* if device mcu send file_result, stop sending block */
		if (g_hlink_upgrade_result != PACKAGE_INVALIDE_ERRCODE) {
			OMIP_LOG_INFO( "device check file notice failed or other fault\n");
			g_hlink_upgrade_result = PACKAGE_INVALIDE_ERRCODE;
			osal_semp_del(g_hlink_ota_semp);
			return HLINK_ERR_COMMON_ERROR;
		}

		uint32_t send_len = (tail_info->code_len - send_file_size) > PACKAGE_CACHE_LEN ? PACKAGE_CACHE_LEN : (tail_info->code_len - send_file_size);
		unsigned char *data_send =(unsigned char *)(g_file_trans.file_buffer + subfile_header->sub_file_offset + send_file_size);

		ret = omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_FILE_MNGR_BLOCK,
            data_send, send_len);
		if(ret != OMIP_OK) {
            omip_printf(OMIP_ERROR, "send HLINK_CMD_FILE_MNGR_BLOCK failed\n");
            osal_semp_del(g_hlink_ota_semp);
            return HLINK_ERR_COMMON_ERROR;
		}
		send_file_size += send_len;
		
		int schedule = (send_file_size * 100) / tail_info->code_len;
		if((schedule > schedule_print) && (0 == schedule%10)) {
			OMIP_LOG_INFO( "send hlink_firmware file completion :%d%%",  schedule);
			schedule_print = schedule;
		}
		osal_task_sleep(PER_BLOCK_SLEEP_TIME);
	}
	
	/* 3. send file block end */
    OMIP_LOG_INFO( "send HLINK_CMD_FILE_MNGR_BLOCK_END to hlink\r\n");
    ret = send_hlink_file_block_end();
    if (ret != HLINK_OK) {
        osal_semp_del(g_hlink_ota_semp);
        return HLINK_ERR_COMMON_ERROR;
    }

	return get_hlink_upgrade_result();
}

int set_ble_upgrade_result(int upgrade_result)
{
	g_file_trans.ble_ota_res = upgrade_result; //蓝牙OTA回复标志置位

    if (osal_semp_post(Mutex_ble_handle) != HLINK_OK) {
        omip_printf(OMIP_ERROR, "post g_ble_ota_semp semp failed\r\n");
        return HLINK_ERR_COMMON_ERROR;
    }
    return HLINK_OK;
}

int get_ble_upgrade_result(void)
{
    int ret;
    g_file_trans.ble_ota_res = PACKAGE_INVALIDE_ERRCODE;

    ret = osal_semp_pend(Mutex_ble_handle, 1000*120); // wait 120 secondss
    if(ret != OSAL_OK) {
        OMIP_LOG_ERROR("pend g_ble_ota_semp semp failed or timeout\r\n");
    }

    osal_semp_del(Mutex_ble_handle);
    return g_file_trans.ble_ota_res;
}


void package_upgrade_process(void* args) //处理手机APP下发的升级包
{
	void *ptask_id =g_file_trans.ble_pack_taskid;
    uint32_t sub_header_cnt =0;
	int result = HLINK_OK;
    uint32_t i = 0, j = 0, offset = 0;
    BINFILE_HEAD_FIXED_S package_header ={0};
    BIN_SUBFILE_HEAD_S * subfile_header =NULL;
    BIN_SUBFILE_HEAD_S   tmp_subheader;
	SEFS *tail_info =NULL;
    uint32_t binfile_head_size =sizeof(BINFILE_HEAD_FIXED_S); //package包头尺寸
    uint32_t subfile_head_size =sizeof(BIN_SUBFILE_HEAD_S); //子文件头尺寸
	int update_mcu_index = -1; 				//是否重启MCU
	int update_ble_flag = 0; 				//是否重启MCU
	unsigned int firmware_size[8] ={0}; 	//每个固件的长度

	OMIP_LOG_INFO( "start to process package...\r\n");
	memcpy(&package_header, g_file_trans.file_buffer,sizeof(BINFILE_HEAD_FIXED_S)); //读取包头
	OMIP_LOG_INFO( "file_desc:%s\r\n",package_header.file_desc);
    package_header.file_len = ntohl(package_header.file_len);
    package_header.sub_file_sum = ntohl(package_header.sub_file_sum);
    package_header.bin_head_size = ntohl(package_header.bin_head_size);
	OMIP_LOG_INFO( "bin_head_size2:%d(0x%04x)\r\n", package_header.bin_head_size, package_header.bin_head_size);
    if(binfile_head_size != package_header.bin_head_size) { //长度有错?
        OMIP_LOG_ERROR("head size(%d) != sizeof(BINFILE_HEAD_FIXED_S)(%d).\r\n",package_header.bin_head_size,binfile_head_size);
        binfile_head_size =package_header.bin_head_size;
    }
	
    offset += binfile_head_size;
	OMIP_LOG_INFO( "subheader offset:%d", offset);
	memcpy(&tmp_subheader,g_file_trans.file_buffer+offset,subfile_head_size); //读取子文件头
    tmp_subheader.sub_file_head_size = ntohl(tmp_subheader.sub_file_head_size);
    if(subfile_head_size != tmp_subheader.sub_file_head_size) { //长度有错?
        OMIP_LOG_ERROR("subfile head size(%d) != sizeof(BIN_SUBFILE_HEAD_S)(%d).\r\n",
								tmp_subheader.sub_file_head_size,subfile_head_size);
        subfile_head_size = tmp_subheader.sub_file_head_size;
    }
	sub_header_cnt = package_header.sub_file_sum; //子文件头个数

	//分包头处理
	subfile_header = omip_malloc(sub_header_cnt*subfile_head_size); //按个数分配内存
	if(subfile_header==NULL) {
		OMIP_LOG_ERROR("malloc failed!(%d)\r\n", (sub_header_cnt*subfile_head_size)); 
		goto exit;
	}
    tail_info =osal_malloc(sub_header_cnt*sizeof(SEFS));
    if(tail_info ==NULL) {
		OMIP_LOG_ERROR("[%s:%d]malloc failed!(%d)\r\n",sub_header_cnt*sizeof(SEFS)); 
		goto exit;
	}
	for(i =0; i <sub_header_cnt && i<8; i++)
	{
		OMIP_LOG_INFO( "subheader:%d", i);
		OMIP_LOG_INFO( "offset:%d", offset);
		memcpy(&subfile_header[i],g_file_trans.file_buffer+offset,subfile_head_size);
		OMIP_LOG_INFO( "sub_file_name:%s", subfile_header[i].sub_file_name);
		offset += subfile_head_size;
		subfile_header[i].sub_file_len = ntohl(subfile_header[i].sub_file_len);
		OMIP_LOG_INFO( "sub_file_len:%ld", subfile_header[i].sub_file_len);
		subfile_header[i].sub_file_offset = ntohl(subfile_header[i].sub_file_offset);
		OMIP_LOG_INFO( "sub_file_offset:%ld", subfile_header[i].sub_file_offset);
		subfile_header[i].sub_file_head_size = ntohl(subfile_header[i].sub_file_head_size);
		OMIP_LOG_INFO( "sub_file_head_size:%ld", subfile_header[i].sub_file_head_size);

		//分包尾处理
		//printf("[%s:%d]tail_info[10]", __FUNCTION__, __LINE__); 
		//print_binary(&tail_info[i],g_file_trans.file_buffer + 0x12238, 10);
		OMIP_LOG_INFO( "tail_info offset:%ld", subfile_header[i].sub_file_offset+subfile_header[i].sub_file_len-sizeof(SEFS));
		memcpy(&tail_info[i], g_file_trans.file_buffer+(subfile_header[i].sub_file_offset+subfile_header[i].sub_file_len-sizeof(SEFS)),sizeof(SEFS));
		OMIP_LOG_INFO( "efs_version:%d", tail_info[i].file_type);
		tail_info[i].efs_version = ntohs(tail_info[i].efs_version);
		OMIP_LOG_INFO( "efs_version:%d", tail_info[i].efs_version);
		tail_info[i].year = ntohs(tail_info[i].year);
		OMIP_LOG_INFO( "date:[%04d-%02d-%02d %02d-%02d-%02d]", 
			tail_info[i].year, tail_info[i].month, tail_info[i].day,
			tail_info[i].hour, tail_info[i].minute, tail_info[i].second);
		tail_info[i].total_len = ntohl(tail_info[i].total_len);
		tail_info[i].code_len = ntohl(tail_info[i].code_len);
		OMIP_LOG_INFO( "code_crc:0x%02x", tail_info[i].code_crc);
		OMIP_LOG_INFO( "efs_crc:0x%02x", tail_info[i].efs_crc);
		firmware_size[i] = tail_info[i].code_len;
		OMIP_LOG_INFO("firmware_size:%d", firmware_size[i]);
	}

	OMIP_LOG_INFO( "start to upgrade subfiles!...");
	for(j = 0; j <sub_header_cnt && j<8; j++)
	{
		OMIP_LOG_INFO("start to ungrade .\r\n", tail_info[j].file_type);
		//是蓝牙固件升级
		if(strcmp("ble_firmware",tail_info[j].file_type)==0 ||
		   strcmp("BTFW",tail_info[j].file_type)==0) 
		{
			OMIP_LOG_INFO("start to ungrade BLE FW.\r\n");
			mcu_blefw_update_task(1,subfile_header[j].sub_file_offset,firmware_size[j], 
				subfile_header[j].sub_file_name, 1); //同步执行
			if(HLINK_OK == get_ble_upgrade_result()) {
				update_ble_flag = 1;
			}
		}
		else if(strcmp("firmware",tail_info[j].file_type)==0) //是MCU固件升级
		{
			//最后处理MCU
			update_mcu_index = j;
		}
		else if(strcmp("hlink_firmware",tail_info[j].file_type) == 0) 
		{
			OMIP_LOG_INFO("start to ungrade hlink_firmware.\r\n");
			int ret = upgrade_hlink_firmware(&subfile_header[j], &tail_info[j], g_file_trans.notice_mid);
			if(HLINK_OK != ret) {
				OMIP_LOG_ERROR("upgrade_hlink_firmware failde.ret=%d.\r\n", ret);
				result = HLINK_ERR_FILE_CHECKSUM_ERROR;
			}
		}
		else {
			OMIP_LOG_ERROR("unsupported upgrade:%s.\r\n", tail_info[j].file_type);
		}
 	}

	
	if(update_mcu_index >= 0 && strcmp("firmware",tail_info[update_mcu_index].file_type)==0) {
		OMIP_LOG_INFO("start to ungrade MCU FW.\r\n");
		char calsha256[65] ={0};
		get_sha256((unsigned char *)g_file_trans.file_buffer +subfile_header[update_mcu_index].sub_file_offset,
			firmware_size[update_mcu_index], calsha256);
		if(memcmp(strlowr(tail_info[update_mcu_index].checksum),strlowr(calsha256), sizeof(tail_info[update_mcu_index].checksum))!=0) { //文件校验出错
			OMIP_LOG_INFO("firmware bin file checksum:%s.\r\n right checksum:%s\r\n", tail_info[update_mcu_index].checksum, calsha256);
			result = HLINK_ERR_FILE_CHECKSUM_ERROR;
		}
		else {
			g_flash_bin = file_addr_init("bin",FILE_BIN_ADDR, firmware_size[update_mcu_index]);
			g_flash_bin->buff = (g_file_trans.file_buffer +subfile_header[update_mcu_index].sub_file_offset);
			save_data_to_file(g_flash_bin); //保存文件到FLASH
			if(NULL != g_flash_bin) {
				free(g_flash_bin); 
				g_flash_bin =NULL;
			}
		}
	}
	
	OMIP_LOG_INFO("send ble upgrade result = %d", result);
	send_ble_file_mngr_result(result, "upgrade result"); //发送文件传输完成通知
	send_ble_file_mngr_result(result, "upgrade result"); //发送文件传输完成通知
	osal_task_sleep(10000); //等待一段时间,等PLC固件升级完成

exit:
	if(subfile_header) osal_free(subfile_header);
	//if(upgrade_order)  osal_free(upgrade_order);
	if(tail_info) 	   osal_free(tail_info);
	if(update_ble_flag) ble_reset();
	if(update_mcu_index >= 0)  system_reset_delay(); //延时重启
	OMIP_LOG_INFO("package update finished.\r\n");
	if(ptask_id !=NULL) free_file_buff(); //是异步调用,释放文件缓存
	if(ptask_id !=NULL) osal_task_kill(ptask_id); //如果是开的线程则释放线程ID
}

int package_upgrade_task() //手机APP包升级任务
{
	
    OMIP_LOG_INFO("package upgreade start!\r\n");
    g_file_trans.ble_pack_taskid = osal_task_create("package_upgrade",(int (*)(void *))package_upgrade_process,NULL,1024*2,NULL,23);
    if(g_file_trans.ble_pack_taskid == NULL) {
		OMIP_LOG_ERROR("task create failed!\r\n"); 
		return -1;
	}
	return 0;
}

static void get_file_mngr_notice(uint8_t ct, uint8_t* data, int len) //处理下发文件通知
{
	if(OMIP_CONTENT_FORMAT_JSON ==ct) //模组日志上传
	{
		strcpy((char *)g_notice_msg.file_type, "__modulelog");
		g_file_trans.notice_size =g_file_trans.received_size =0;
		mcu_general_send_ble(HLINK_CMD_FILE_MNGR_NOTICE,ct,data,len); //原封不动转发给蓝牙
		return;
	}
    if(OMIP_CONTENT_FORMAT_BINARY !=ct || len!=sizeof(file_mngr_notice))
    {
        OMIP_LOG_INFO("file notice not support ct:%d, datalen:%d\r\n", ct,len);
		send_file_mngr_result(OMIP_CONTENT_FORMAT_BINARY!=ct? OMIP_INVALID_FORMAT : OMIP_INVALID_PARA); //发送文件传输完成通知
        return;
    }
	if(g_file_trans.trans_status==1 && abs(LOS_Tick2MS(LOS_TickCountGet())-g_file_trans.last_activetm) <180000) //文件正在传输
	{
        OMIP_LOG_INFO( "file transfer is busy!\r\n");
		send_file_mngr_result(HLINK_ERR_SYSTEM_BUSY); //发送文件传输完成通知
        return;
	}
	
    file_mngr_notice *notice_msg =(file_mngr_notice *)data;
    memset_s(&g_notice_msg,sizeof(file_mngr_notice),0,sizeof(file_mngr_notice));
	memcpy_s(&g_notice_msg,sizeof(file_mngr_notice),notice_msg,sizeof(file_mngr_notice));
	OMIP_LOG_INFO("file_name:%s, file_type:%s", notice_msg->file_name, notice_msg->file_type);

	free_file_buff(); //释放之前的文件缓存
	g_file_trans.notice_size =notice_msg->file_size; //通知文件长度
    g_file_trans.received_size =0; //已经接收长度
	memcpy(g_file_trans.checksum,notice_msg->check_sum,HLINK_FILE_CHECK_SUM_LEN_MAX);
	g_file_trans.file_buffer =(char *)malloc(g_file_trans.notice_size +1);
	if(!g_file_trans.file_buffer) //分配文件缓存失败
	{
		omip_printf(OMIP_ERROR,"[%s:%d]malloc(%d) failed!\r\n",__FUNCTION__,__LINE__,g_file_trans.notice_size);
		send_file_mngr_result(HLINK_ERR_FILE_NO_SPACE); //发送文件传输完成通知
		return;
	}
	g_file_trans.trans_status =1;
	g_file_trans.last_activetm =LOS_Tick2MS(LOS_TickCountGet());
	if(strcmp((char *)g_notice_msg.file_type,"firmware") ==0) //是MCU升级固件
		mcu_stop_local_flow();
	else if(strcmp((char *)g_notice_msg.file_type,"ctlLogic") ==0) //是策略文件
        mcu_only_stop_local_flow();
	OMIP_LOG_INFO("file notice!file type:%s,len:%d\r\n", g_notice_msg.file_type,g_file_trans.notice_size);
}

static void get_file_mngr_block(uint8_t ct, uint8_t* data, int len) //文件数据处理
{
	static int schedule_print = 0;
	if(strcmp((char *)g_notice_msg.file_type,"__modulelog")==0) //模组日志
	{
		mcu_general_send_ble(HLINK_CMD_FILE_MNGR_BLOCK,ct,data,len); //原封不动转发给蓝牙
		return;
	}
	if(!(g_file_trans.file_buffer) || g_file_trans.received_size+len >g_file_trans.notice_size) {
		OMIP_LOG_ERROR("file_buffer(%p) is null or overflow", g_file_trans.file_buffer);
		return; //缓存分配失败或长度溢出
	}
    memcpy(g_file_trans.file_buffer+g_file_trans.received_size,data,len);
	g_file_trans.received_size += len;
	
	int schedule = (g_file_trans.received_size * 100) / g_file_trans.notice_size;
	if((schedule > schedule_print) && (0 == schedule%10)) {
		OMIP_LOG_INFO( "received from gateway %s file completion :%d%%", g_notice_msg.file_type, schedule);
		schedule_print = schedule;
	}
	if(schedule_print >= 100) {
		schedule_print = 0;
	}
}

static void get_file_mngr_block_end(uint8_t ct, uint8_t* data, int len) //文件数据传输完毕
{
	omip_printf(OMIP_INFO,"[%s:%d]file transfer completed! len:%ld\r\n",__FUNCTION__,__LINE__,g_file_trans.received_size);
	if(strcmp((char *)g_notice_msg.file_type,"__modulelog")==0) //模组日志,原封不动转发给蓝牙
	{
		mcu_general_send_ble(HLINK_CMD_FILE_MNGR_BLOCK_END,ct,data,len);
		return;
	}

	//缓存分配失败
	if(!g_file_trans.file_buffer) {
		send_file_mngr_result(OMIP_FILE_NO_SPACE); 
		goto free_file;
	}
	
	char calsha256[65] ={0};
	get_sha256((unsigned char *)g_file_trans.file_buffer,g_file_trans.notice_size,calsha256); //计算SHA256
	if(strcmp(strlowr(g_file_trans.checksum),strlowr(calsha256))!=0) { //文件校验出错
		omip_printf(OMIP_INFO,"wrong bin file checksum:%s\r\nright checksum:%s\r\n",g_file_trans.checksum,calsha256);
		send_file_mngr_result(HLINK_ERR_FILE_CHECKSUM_ERROR); //发送文件传输完成通知
		if(strcmp((char *)g_notice_msg.file_type,"firmware")==0) {
			mcu_start_local_flow(); //是升级固件
		}
		else if(strcmp((char *)g_notice_msg.file_type,"ctlLogic")==0) {
			mcu_only_start_local_flow(); //是策略文件
		}
		goto free_file;
	}
	OMIP_LOG_INFO( "file_type:%s", g_notice_msg.file_type);
	if(strcmp((char *)g_notice_msg.file_type,"firmware")==0) //是升级固件
	{
		osal_task_sleep(4000);
		g_flash_bin =file_addr_init("bin",FILE_BIN_ADDR,g_file_trans.notice_size);
		g_flash_bin->buff =g_file_trans.file_buffer;
		save_data_to_file(g_flash_bin); //保存文件到FLASH
		if(NULL !=g_flash_bin) {free(g_flash_bin); g_flash_bin =NULL;}
		send_file_mngr_result(OMIP_FILE_OK); //发送文件传输完成通知
		for(int i = 0; i < 10; i++)
		{
			if(g_file_trans.ble_ota_taskid == NULL) {
				break;
			}
			OMIP_LOG_INFO( "wait ble_ota_taskid exit");
			osal_task_sleep(1000);
		}
		system_reset_delay(); //延时重启
	}
	else if(strcmp((char *)g_notice_msg.file_type,"ctlLogic")==0) //是策略文件
	{
		g_flash_flow =file_addr_init("flow",FILE_FLOW_ADDR,g_file_trans.notice_size);
		g_flash_flow->buff =g_file_trans.file_buffer;
		save_data_to_file(g_flash_flow); //保存文件到FLASH
		if(NULL!=g_flash_flow) {free(g_flash_flow); g_flash_flow =NULL;}
		cengine_parse_metadata(g_file_trans.file_buffer,strlen(g_file_trans.file_buffer));
		cengine_process_init();
		send_file_mngr_result(OMIP_FILE_OK); //发送文件传输完成通知
	}
	else if(strcmp((char *)g_notice_msg.file_type,"ble_firmware")==0
			|| strcmp((char *)g_notice_msg.file_type,"BTFW")==0) //是蓝牙固件文件
	{
		OMIP_LOG_INFO("start to upgrade BLE FW.\r\n");
        if(mcu_blefw_update_task(0,0,g_file_trans.notice_size, (char *)g_notice_msg.file_name, 1)==-1) //同步执行
        {
			OMIP_LOG_ERROR("upgrade ble failed\r\n");
			send_file_mngr_result(HLINK_ERR_SYSTEM_BUSY);
			free_file_buff(); //释放文件缓存
        }
		else
		{
			OMIP_LOG_ERROR("waite ble ack, timeout time 120 seconds\r\n");
			if(HLINK_OK == get_ble_upgrade_result()) {
				ble_reset();
				send_file_mngr_result(HLINK_OK); //网关侧升级结果通知
			}
			else {
				send_file_mngr_result(HLINK_WAIT_DEVICE_RSP_TIMEOUT); //网关侧升级结果通知
				OMIP_LOG_ERROR("waite ble ack timeout\r\n");
			}
			free_file_buff(); //释放文件缓存
		}
		return;
	}
    else if(strcmp((char *)g_notice_msg.file_type,"package")==0 && g_file_trans.file_buffer) //是升级包
    {
    	char calsha256[65] ={0};
		get_sha256((unsigned char *)g_file_trans.file_buffer,g_file_trans.notice_size,calsha256); //计算SHA256
		if(strcmp(strlowr(g_file_trans.checksum),strlowr(calsha256))!=0) { //文件校验出错
			omip_printf(OMIP_INFO,"wrong bin file checksum:%s\r\nright checksum:%s\r\n",g_file_trans.checksum,calsha256);
			send_file_mngr_result(HLINK_ERR_FILE_CHECKSUM_ERROR); //发送蓝牙文件传输完成通知
			free_file_buff(); //释放文件缓存
			return;
		}
		
        if(package_upgrade_task()==-1) //新开一个任务处理手机APP包升级,内部会释放文件缓存
        {
			send_file_mngr_result(HLINK_ERR_SYSTEM_BUSY);
			free_file_buff(); //释放文件缓存
        }
		else
		{
			send_file_mngr_result(OMIP_FILE_OK); //发送文件传输完成通知
		}
		return;
    }

free_file:
	free_file_buff(); //释放文件缓存
}

static void get_ble_file_mngr_notice(uint8_t ct, uint8_t* data, int len) //处理蓝牙下发文件通知
{
	cJSON *notice_cmd =cJSON_Parse((char*)data);
	cJSON *paras =(notice_cmd? cJSON_GetObjectItem(notice_cmd,"paras") : NULL);
	if (OMIP_CONTENT_FORMAT_JSON !=ct || notice_cmd==NULL || paras==NULL)
	{
        omip_printf(OMIP_ERROR,"[%s:%d]not support ct:%d\n",__FUNCTION__,__LINE__,ct);
		send_ble_file_mngr_result(HLINK_ERR_INVALID_FORMAT, TRANSFER_RESULT); //发送蓝牙文件传输完成通知
        goto exit;
	}
	
	//char *srv =GET_JSON_ITEM(notice_cmd,"srv",valuestring,"");
	//char *cmd =GET_JSON_ITEM(notice_cmd,"cmd",valuestring,"");
	int   mid =GET_JSON_ITEM(notice_cmd,"mid",valueint,-1);
    char *operate_code =GET_JSON_ITEM(paras,"operateCode",valuestring,"");
    char *file_name    =GET_JSON_ITEM(paras,"fileName",valuestring,"");
    char *file_type    =GET_JSON_ITEM(paras,"fileType",valuestring,"");
    int   file_size    =GET_JSON_ITEM(paras,"fileSize",valueint,-1);
    char *file_version =GET_JSON_ITEM(paras,"fileVersion",valuestring,"");
    char *check_sum    =GET_JSON_ITEM(paras,"checkSum",valuestring, "");
	memset_s(&g_notice_msg,sizeof(file_mngr_notice),0,sizeof(file_mngr_notice));
    (void)memcpy_s(g_notice_msg.operate_code, HLINK_FILE_OPERATE_CODE_LEN_MAX, operate_code, strlen(operate_code));
    (void)memcpy_s(g_notice_msg.file_name, HLINK_FILE_NAME_LEN_MAX, file_name, strlen(file_name));
    (void)memcpy_s(g_notice_msg.file_type, HLINK_FILE_TYPE_LEN_MAX, file_type, strlen(file_type));
    g_notice_msg.file_size =file_size;
    (void)memcpy_s(g_notice_msg.file_version, HLINK_FILE_VERSION_LEN_MAX, file_version, strlen(file_version));
    (void)memcpy_s(g_notice_msg.check_sum, HLINK_FILE_CHECK_SUM_LEN_MAX, check_sum, strlen(check_sum));
	
	OMIP_LOG_INFO("ble file_name:%s, file_type:%s", g_notice_msg.file_name, g_notice_msg.file_type);
	if(strcmp((char *)g_notice_msg.operate_code,"download")==0 &&strcmp((char *)g_notice_msg.file_type,"devcert")!=0) //升级包
	{
		if(g_file_trans.trans_status==1 && abs(LOS_Tick2MS(LOS_TickCountGet())-g_file_trans.last_activetm) <180000) //文件正在传输
		{
			omip_printf(OMIP_INFO,"[%s:%d]file transfer is busy!\r\n",__FUNCTION__,__LINE__,ct,len);
			send_ble_file_mngr_result(HLINK_ERR_SYSTEM_BUSY, TRANSFER_RESULT); //发送蓝牙文件传输完成通知
			goto exit;
		}
	}
	free_file_buff(); //释放之前的文件缓存
	g_file_trans.notice_size =g_notice_msg.file_size; //文件长度
    g_file_trans.received_size =0; //已经接收长度
    g_file_trans.notice_mid =mid;  //文件通知的MID
    memcpy(g_file_trans.checksum,g_notice_msg.check_sum,HLINK_FILE_CHECK_SUM_LEN_MAX);
	if(strcmp((char *)g_notice_msg.operate_code,"download")==0) //下载
	{
		if(strcmp((char *)g_notice_msg.file_type,"package")==0) //升级包
		{
			g_file_trans.file_buffer =(char *)malloc(g_file_trans.notice_size);
			if(!g_file_trans.file_buffer)
			{
				omip_printf(OMIP_ERROR,"[%s:%d]malloc(%d) failed!\r\n",__FUNCTION__,__LINE__,g_file_trans.notice_size);
				send_ble_file_mngr_result(HLINK_ERR_FILE_NO_SPACE, TRANSFER_RESULT); //发送蓝牙文件传输完成通知
				goto exit;
			}
			g_file_trans.trans_status =1;
			g_file_trans.last_activetm =LOS_Tick2MS(LOS_TickCountGet());
		}
		else if(strcmp((char *)g_notice_msg.file_type,"devcert")==0) //证书,转发到模组
		{
            if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_JSON,HLINK_CMD_FILE_MNGR_NOTICE,data,len)!=OMIP_OK)
            {
                omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
				send_ble_file_mngr_result(HLINK_ERR_COMMON_ERROR, TRANSFER_RESULT); //发送蓝牙文件传输完成通知
				goto exit;
            }
		}
	}
	else if(strcmp((char *)g_notice_msg.operate_code,"upload")==0) //蓝牙上传(不知道什么用)
	{
		strcpy((char *)g_notice_msg.file_type,"__bleupload");
		mcu_general_send_ble(HLINK_CMD_FILE_MNGR_NOTICE,OMIP_CONTENT_FORMAT_JSON,data,len); //向蓝牙HLINK发送数据
	}
	OMIP_LOG_INFO( "file notice!file type:%s, operateCode:%s\r\n", g_notice_msg.file_type, g_notice_msg.operate_code);
exit:
	if(notice_cmd) cJSON_Delete(notice_cmd);
}

static void get_ble_file_mngr_block(uint8_t ct, uint8_t* data, int len) //蓝牙文件数据处理
{
	static int schedule_print = 0;
	if(strcmp((char *)g_notice_msg.file_type,"__bleupload")==0) //蓝牙上传(不知道什么用)
	{
		OMIP_LOG_DEBUG( "opcode:%s, file_type:%d", g_notice_msg.operate_code, g_notice_msg.file_type);
		mcu_general_send_ble(HLINK_CMD_FILE_MNGR_BLOCK,OMIP_CONTENT_FORMAT_JSON,data,len); //向蓝牙HLINK发送数据
		return;
	}
    if(strcmp((char *)g_notice_msg.file_type,"package")==0) //是升级包
    {
		if(!(g_file_trans.file_buffer) || g_file_trans.received_size+len >g_file_trans.notice_size) return; //缓存分配失败或长度溢出
		memcpy(g_file_trans.file_buffer+g_file_trans.received_size,data,len);
		g_file_trans.received_size +=len;
		int schedule = (g_file_trans.received_size * 100) / g_file_trans.notice_size;
		if((schedule > schedule_print) && (0 == schedule%10)) {
			OMIP_LOG_INFO( "received from ble %s file completion :%d%%", g_notice_msg.file_type, schedule);
			schedule_print = schedule;
		}
		if(schedule_print >= 100) {
			schedule_print = 0;
		}
    }
	else if(strcmp((char *)g_notice_msg.file_type,"devcert")==0) //证书,转发到模组
	{
		omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_BINARY,HLINK_CMD_FILE_MNGR_BLOCK,data,len);
	}
}

static void get_ble_file_mngr_block_end(uint8_t ct, uint8_t* data, int len) //蓝牙文件数据传输完毕
{
	omip_printf(OMIP_INFO,"[%s:%d]file transfer completed! len:%ld\r\n",__FUNCTION__,__LINE__,g_file_trans.received_size);
	if(strcmp((char *)g_notice_msg.file_type,"__bleupload")==0) //蓝牙上传(不知道什么用)
	{
		mcu_general_send_ble(HLINK_CMD_FILE_MNGR_BLOCK_END,OMIP_CONTENT_FORMAT_JSON,data,len); //向蓝牙HLINK发送数据
		return;
	}
    if(strcmp((char *)g_notice_msg.file_type,"package")==0 && g_file_trans.file_buffer) //是升级包
    {
    	char calsha256[65] ={0};
		get_sha256((unsigned char *)g_file_trans.file_buffer,g_file_trans.notice_size,calsha256); //计算SHA256
		if(strcmp(strlowr(g_file_trans.checksum),strlowr(calsha256))!=0) { //文件校验出错
			omip_printf(OMIP_INFO,"wrong bin file checksum:%s\r\nright checksum:%s\r\n",g_file_trans.checksum,calsha256);
			send_ble_file_mngr_result(HLINK_ERR_FILE_CHECKSUM_ERROR, TRANSFER_RESULT); //发送蓝牙文件传输完成通知
			free_file_buff(); //释放文件缓存
			return;
		}
        if(package_upgrade_task()==-1) //新开一个任务处理手机APP包升级,内部会释放文件缓存
        {
			send_ble_file_mngr_result(HLINK_ERR_SYSTEM_BUSY, TRANSFER_RESULT);
			free_file_buff(); //释放文件缓存
        }
		else
		{
			send_ble_file_mngr_result(HLINK_OK, TRANSFER_RESULT); //发送文件传输完成通知
		}
    }
	else if(strcmp((char *)g_notice_msg.file_type,"devcert")==0) //证书,转发到模组
	{
		if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_BINARY,HLINK_CMD_FILE_MNGR_BLOCK_END,data,len) !=OMIP_OK)
			omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
	}
}


static void mcu_recv_ble_file_mngr_result_process(uint8_t vc, uint8_t ct, uint8_t *data, unsigned int len)
{
	if(len == 5)
	{
		OMIP_LOG_INFO("ble upgrade finished %d\r\n", data[0]);
		// package upgrade from app
		if (set_ble_upgrade_result(data[0]) != HLINK_OK) {
		    OMIP_LOG_ERROR("set ble upgrade result failed\n");
		}
	}
	else
	{
		OMIP_LOG_ERROR("ble file mngr result error\n");
	}
}


void get_hlink_info(uint8_t ct, uint8_t* data, int len)
{
	int explen =sizeof(moudle_online_info);
    if(OMIP_CONTENT_FORMAT_BINARY!=ct) {omip_printf(OMIP_INFO,"[%s:%d]only support ct[%d]\r\n",__FUNCTION__,__LINE__,OMIP_CONTENT_FORMAT_BINARY); return;}
    if(len !=explen) {omip_printf(OMIP_INFO,"[%s:%d]register failed!len[%d],expect len[%d]\r\n",__FUNCTION__,__LINE__,len,explen); return;}
    moudle_online_info *online_msg = (moudle_online_info *)data;
    memset(&g_hlink_info, 0 ,sizeof(moudle_online_info));
    unsigned char  hiv[HLINK_HIV_LEN_MAX + 1] = {0};
    unsigned char  fwv[HLINK_FWV_LEN_MAX + 1] = {0};
    unsigned char  hwv[HLINK_HWV_LEN_MAX + 1] = {0};
    memcpy(hiv, online_msg->hiv,HLINK_HIV_LEN_MAX);
    memcpy(fwv,online_msg->fwv, HLINK_FWV_LEN_MAX);
    memcpy(hwv, online_msg->hwv,HLINK_HWV_LEN_MAX);
    OMIP_LOG_INFO("[%s:%d]hiv:%s, fwv:%s, hwv:%s\r\n",__FUNCTION__,__LINE__,hiv,fwv,hwv);
    memcpy(&g_hlink_info, online_msg, sizeof(moudle_online_info));
}

void send_device_reg_req_json()
{
    cJSON *root = NULL;
    root = cJSON_CreateObject();
    if (root == NULL) {
        OMIP_LOG_ERROR("json create object failed\n");
        return;
    }

    cJSON_AddStringToObject(root, "sn", g_mcu_sn);
    cJSON_AddStringToObject(root, "model", "vav-10");
    cJSON_AddStringToObject(root, "manu", "1003");
    cJSON_AddStringToObject(root, "name", g_mcu_sn);
    cJSON_AddStringToObject(root, "desc", "VAV");
    cJSON_AddStringToObject(root, "rfv", "1.00");
    cJSON_AddStringToObject(root, "mac", "00112233445566");
    cJSON_AddStringToObject(root, "fwv", g_mcu_version);
    cJSON_AddStringToObject(root, "hwv", "1.01");
    cJSON_AddStringToObject(root, "swv", "1.01");
    cJSON_AddStringToObject(root, "btv", g_ble_version);

    if(strcmp((char*)g_hlink_info.fwv, "WiFi.ailian") == 0)
    {
        cJSON_AddStringToObject(root, "protType", "WiFi");
    }
    else if(strcmp((char*)g_hlink_info.fwv, "PLC.huawei") == 0)
    {
        cJSON_AddStringToObject(root, "protType", "PLC");
    }
    else
    {
        cJSON_AddStringToObject(root, "protType", "ETH");
    }
    cJSON_AddNumberToObject(root, "accept_ct", HLINK_SERVICE_CT_ASN1_UPER);

    char* dev_reg = cJSON_PrintUnformatted(root);

    OMIP_LOG_INFO("dev_reg is send json: %s\r\n", dev_reg);

    if (omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_JSON, HLINK_CMD_DEV_REG_REQ, (uint8_t*)dev_reg, strlen(dev_reg)+1) != OMIP_OK) //received online from hlink module, send dev_reg to hlink module
    {
        omip_printf(OMIP_ERROR, "====omip_api_send HLINK_CMD_DEV_REG_REQ failed!\r\n");
    }
    omip_free(dev_reg);
    cJSON_Delete(root);
}

void send_device_reg_req()
{
    g_flash_sn =file_addr_init("bksn",FILE_BL_BKSN_ADDR, FILE_BL_BKSN_SIZE);
    g_flash_sn->buff = (char *)malloc(sizeof(uint8_t)*g_flash_sn->size);
    read_data_from_file(g_flash_sn);
    device_register_req dev_info;
	memset(&dev_info,0,sizeof(dev_info));

    memcpy(dev_info.sn, g_flash_sn->buff, 40);
    memcpy(dev_info.model, "vav-10", strlen("vav-10"));
    memcpy(dev_info.manu, "1003", strlen("1003"));
    memcpy(dev_info.name,g_flash_sn->buff, 32);
    memcpy(dev_info.desc, "VAV", strlen("VAV"));
    memcpy(dev_info.rfv, "1.00", strlen("1.00"));
    memcpy(dev_info.mac, "00112233445566", strlen("00112233445566"));
    memcpy(dev_info.fwv, g_mcu_version, strlen(g_mcu_version));
    memcpy(dev_info.hwv, "1.01", strlen("1.01"));
    memcpy(dev_info.swv, "1.01", strlen("1.01"));
    memcpy(dev_info.protType, "", strlen(""));
    dev_info.accept_ct = HLINK_SERVICE_CT_ASN1_UPER;
#ifdef EXTEND_DEVICE
    unsigned short ex_dev_type = 1;
    char *ex_dev_desc = "ex_dev_desc";
    unsigned int ex_dev_desc_len = strlen(ex_dev_desc);
    unsigned int dev_info_len = sizeof(device_register_req) + ex_dev_desc_len - 1 ;
#else
    unsigned int dev_info_len = sizeof(device_register_req);
#endif
    if(strcmp((char*)g_hlink_info.fwv, "WiFi.ailian") == 0)
        snprintf((char*) dev_info.protType, HLINK_PROT_TYPE_LEN_MAX, "%s", "WiFi");
    else if(strcmp((char*)g_hlink_info.fwv, "PLC.huawei") == 0)
        snprintf((char*) dev_info.protType, HLINK_PROT_TYPE_LEN_MAX, "%s", "PLC");
    else
        snprintf((char*) dev_info.protType, HLINK_PROT_TYPE_LEN_MAX, "%s", "ETH");
	//received online from hlink module, send dev_reg to hlink module
    if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_BINARY,HLINK_CMD_DEV_REG_REQ,(uint8_t*)&dev_info, dev_info_len)!=OMIP_OK)
        omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
    free_w25flash_t(&g_flash_sn);
}

void get_dev_reg_rsp(uint8_t ct, uint8_t* data, int len)
{
    if (ct == OMIP_CONTENT_FORMAT_BINARY)
    {
        if (len != sizeof(device_register_rsp))
        {
            OMIP_LOG_ERROR("device register failed,len [%d] expect len[%d]!\n", len, sizeof(device_register_rsp));
            return;
        }

        device_register_rsp *dev_reg_rsp = (device_register_rsp *)data;
        if(HLINK_DEV_REG_SUCC == dev_reg_rsp->errcode)
        {
            OMIP_LOG_INFO("device register successed!\n");
        }
        else
        {
            OMIP_LOG_ERROR("device register failed,errcode[%d]!\n", dev_reg_rsp->errcode);
        }
    }
    else if(ct == OMIP_CONTENT_FORMAT_JSON)
    {
        cJSON* root = cJSON_Parse((char*) data);
        if(root == NULL)
        {
            OMIP_LOG_INFO("received dev_reg_rsp is not correct\n");
            return;
        }
        int errcode = GET_JSON_ITEM(root, "errcode", valueint, -2);
        cJSON_Delete(root);
        if(HLINK_DEV_REG_SUCC == errcode)
        {
            OMIP_LOG_INFO("device register successed!\n");
        }
        else
        {
            OMIP_LOG_ERROR("device register failed,errcode[%d]!\n", errcode);
        }
    }
    else
    {
        OMIP_LOG_INFO("format is not support ct[%d] yet\n",ct);
    }
}

void send_dev_update_req_asn_uper()
{
    char asn1_uper_update_dev[] = {
        0X85, 0XE8, 0XA2, 0X42, 0X61, 0X89, 0X81, 0XA2, 0X09, 0X81, 0X91, 0X81, 0X81, 0X8A, 0X29,
        0XC1, 0XC1, 0XC1, 0XC1, 0XC1, 0XC1, 0XC1, 0XC0, 0X00, 0X29, 0X89, 0X81, 0X71, 0X81, 0X88,
        0X2A, 0XB2, 0X2A, 0X91, 0X72, 0X18, 0X7A, 0XB1, 0X89, 0X81, 0X82, 0X91, 0X81, 0X81, 0X8A,
        0X19, 0X81, 0X8A, 0X11, 0X81, 0X89, 0X80, 0X16, 0X86, 0X9C, 0X5A, 0X68, 0X68, 0X5A, 0X60,
        0X60, 0X66, 0X5A, 0X94, 0X04, 0X94, 0X62, 0X04, 0X62, 0X8C, 0X08, 0X62, 0X82, 0X60, 0X66,
        0X05, 0XE0, 0X53, 0X43, 0X83, 0X52, 0XD3, 0X10, 0X11, 0XC0, 0X18, 0X08, 0X0C, 0X08, 0XB4,
        0X9C, 0X5A, 0XA8, 0X06, 0XC2, 0XD0, 0XEA, 0X0A, 0X82, 0X90, 0XAA, 0X62, 0X60, 0X40, 0X18,
        0X08, 0X0C, 0X08, 0XB4, 0X9C, 0X5A, 0XA8, 0X06, 0XC2, 0XD0, 0XEA, 0X0A, 0X82, 0X90, 0XAA,
        0X62, 0X60};
    if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_ASN1_UPER,HLINK_CMD_DEV_INFO_UPDATE,(uint8_t*)asn1_uper_update_dev,sizeof(asn1_uper_update_dev))!=OMIP_OK)
        omip_printf(OMIP_ERROR,"[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
}

void send_dev_update_req_asn_der()
{
    char asn1_der_update_dev[] = {
        0X30, 0X81, 0XA7, 0XA0, 0X57, 0X80, 0X14, 0X48, 0X4C, 0X31, 0X30, 0X34, 0X41, 0X30, 0X32,
        0X30, 0X30, 0X31, 0X45, 0X38, 0X38, 0X38, 0X38, 0X38, 0X38, 0X38, 0X38, 0X85, 0X00, 0X87,
        0X05, 0X31, 0X30, 0X2E, 0X30, 0X31, 0X88, 0X05, 0X56, 0X45, 0X52, 0X2E, 0X43, 0X89, 0X0F,
        0X56, 0X31, 0X30, 0X30, 0X52, 0X30, 0X30, 0X31, 0X43, 0X30, 0X31, 0X42, 0X30, 0X31, 0X30,
        0X8A, 0X01, 0X00, 0XAC, 0X1B, 0X80, 0X0B, 0X43, 0X4E, 0X2D, 0X34, 0X34, 0X2D, 0X30, 0X30,
        0X33, 0X2D, 0X4A, 0X81, 0X02, 0X4A, 0X31, 0X82, 0X02, 0X31, 0X46, 0X83, 0X04, 0X31, 0X41,
        0X30, 0X33, 0XA1, 0X4C, 0X30, 0X29, 0X80, 0X01, 0X02, 0X81, 0X05, 0X34, 0X38, 0X35, 0X2D,
        0X31, 0X82, 0X01, 0X1C, 0XA3, 0X1A, 0X30, 0X18, 0X80, 0X01, 0X01, 0X81, 0X01, 0X02, 0X82,
        0X04, 0X5A, 0X4E, 0X2D, 0X54, 0X83, 0X03, 0X61, 0X68, 0X75, 0X84, 0X05, 0X41, 0X48, 0X55,
        0X31, 0X30, 0X30, 0X1F, 0X80, 0X01, 0X00, 0XA3, 0X1A, 0X30, 0X18, 0X80, 0X01, 0X01, 0X81,
        0X01, 0X02, 0X82, 0X04, 0X5A, 0X4E, 0X2D, 0X54, 0X83, 0X03, 0X61, 0X68, 0X75, 0X84, 0X05,
        0X41, 0X48, 0X55, 0X31, 0X30};
    if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_ASN1_DER,HLINK_CMD_DEV_INFO_UPDATE,(uint8_t*)asn1_der_update_dev,sizeof(asn1_der_update_dev))!=OMIP_OK)
        omip_printf(OMIP_ERROR,"[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
}

void get_dev_update_rsp(uint8_t ct, uint8_t* data, int len)
{
	cJSON *root =NULL;
	char *dev_update_rsp =NULL;
    switch(ct) {
        case OMIP_CONTENT_FORMAT_JSON:
            root =cJSON_Parse((char*) data);
            if(root==NULL) {omip_printf(OMIP_INFO,"[%s:%d]invalid JSON format.\r\n",__FUNCTION__,__LINE__); return;}
            dev_update_rsp = cJSON_PrintUnformatted(root);
            omip_printf(OMIP_INFO,"[%s:%d]OMIP_CONTENT_FORMAT_JSON:%s\r\n",__FUNCTION__,__LINE__,dev_update_rsp);
            omip_free(dev_update_rsp);
            cJSON_Delete(root);
            break;
        case OMIP_CONTENT_FORMAT_ASN1_DER:
            omip_printf(OMIP_INFO,"[%s:%d]CONTENT_FORMAT_ASN1_DER,len:%d.\r\n",__FUNCTION__,__LINE__,len);
            break;
        case OMIP_CONTENT_FORMAT_ASN1_UPER:
			omip_printf(OMIP_INFO,"[%s:%d]CONTENT_FORMAT_ASN1_UPER,len:%d.\r\n",__FUNCTION__,__LINE__,len);
            break;
        default:
			omip_printf(OMIP_INFO,"[%s:%d]not support ct[%d] yet.\r\n",__FUNCTION__,__LINE__,ct);
            break;
    }
}

void send_add_extdev_req()
{//{"devInfos":[{"sn":"00E0FC018008-001","model":"light-xxx","devType":"light","manu":"minghaotian","name":"xxxx","desc":"light in J12A05","mac":"","hiv":"1.0","fwv":"10.01","hwv":"VER.C","swv":"V100R001C01B010","prototype":1,"status":"online","location":{"region":"�й���","country":"�й�","provice":"�㶫ʡ","city":"������","campus":"����","building":"J1","room":"1A03","coordinate":"���ȣ�ά��"}}]}
    int extdev_num =1;
    cJSON *item_devinfo =NULL,*item_devinfo_location =NULL;
    cJSON *root = cJSON_CreateObject();
    cJSON *item_devinfo_array = cJSON_CreateArray();
    for(int i = 1; i <= extdev_num; i++)
    {
        char extdev_sn[HLINK_SN_LEN_MAX]= {0};
        snprintf(extdev_sn, HLINK_SN_LEN_MAX - 1, "%s-%03d", MCU_DEVICE_SN, i);
        item_devinfo = cJSON_CreateObject();
        item_devinfo_location = cJSON_CreateObject();
        if(item_devinfo==NULL ||item_devinfo_location==NULL)
        {
            omip_printf(OMIP_ERROR,"[%s:%d]cJSON_CreateObject failed!\r\n",__FUNCTION__,__LINE__);
            goto failed_exit;
        }
        cJSON_AddStringToObject(item_devinfo, "sn", extdev_sn);
        cJSON_AddStringToObject(item_devinfo, "model", "light-xxx");
        cJSON_AddStringToObject(item_devinfo, "devType", "light");
        cJSON_AddStringToObject(item_devinfo, "manu", "minghaotian");
        cJSON_AddStringToObject(item_devinfo, "name", "xxxx");
        cJSON_AddStringToObject(item_devinfo, "desc", "light in J12A05");
        cJSON_AddStringToObject(item_devinfo, "mac", "");
        cJSON_AddStringToObject(item_devinfo, "hiv", (char*)g_hlink_info.hiv);
        cJSON_AddStringToObject(item_devinfo, "fwv", "10.01");
        cJSON_AddStringToObject(item_devinfo, "hwv", "VER.C");
        cJSON_AddStringToObject(item_devinfo, "swv", "V100R001C01B010");
        if(strcmp((char*)g_hlink_info.fwv,"WiFi.ailian")==0) 		cJSON_AddStringToObject(item_devinfo,"protType","WiFi");
        else if(strcmp((char*)g_hlink_info.fwv,"PLC.huawei")==0)	cJSON_AddStringToObject(item_devinfo,"protType","PLC");
        else														cJSON_AddStringToObject(item_devinfo,"protType","ETH");
        cJSON_AddStringToObject(item_devinfo, "status", "offline");
        cJSON_AddStringToObject(item_devinfo_location, "region", "�й���");
        cJSON_AddStringToObject(item_devinfo_location, "country", "�й�");
        cJSON_AddStringToObject(item_devinfo_location, "provice", "�㶫ʡ");
        cJSON_AddStringToObject(item_devinfo_location, "city", "������");
        cJSON_AddStringToObject(item_devinfo_location, "campus", "����");
        cJSON_AddStringToObject(item_devinfo_location, "building", "J1");
        cJSON_AddStringToObject(item_devinfo_location, "room", "1A03");
        cJSON_AddStringToObject(item_devinfo_location, "coordinate", "���ȣ�ά��");
        cJSON_AddItemToObject(item_devinfo, "location", item_devinfo_location);
        cJSON_AddItemToArray(item_devinfo_array, item_devinfo);
    }
    cJSON_AddItemToObject(root,"devInfos",item_devinfo_array);
    char* addextdev_char =cJSON_PrintUnformatted(root);
	OMIP_LOG_INFO("extdev add:%s\r\n", addextdev_char);
    if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_JSON, HLINK_CMD_EXTDEV_ADD, (uint8_t *)addextdev_char, strlen(addextdev_char)+1) != OMIP_OK)
        omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
    omip_free(addextdev_char);
    cJSON_Delete(root);
    return;
failed_exit:
    if (item_devinfo)			cJSON_Delete(item_devinfo);
    if (item_devinfo_location)	cJSON_Delete(item_devinfo_location);
    if (item_devinfo_array)		cJSON_Delete(item_devinfo_array);
    if (root)					cJSON_Delete(root);
}

void send_update_extdev_req()
{//{"devInfos":[{"sn":"00E0FC018008-001","model":"light-xxx","devType":"light","manu":"minghaotian","name":"xxxx","desc":"light in J12A05","mac":"","hiv":"1.0","fwv":"10.01","hwv":"VER.C","swv":"V100R001C01B010","prototype":1,"status":"online","location":{"region":"�й���","country":"�й�","provice":"�㶫ʡ","city":"������","campus":"����","building":"J1","room":"1A03","coordinate":"���ȣ�ά��"}}]}
    int extdev_num = 1;
    cJSON* item_devinfo = NULL;
    cJSON* item_devinfo_location = NULL;
    cJSON *root =cJSON_CreateObject();
    cJSON *item_devinfo_array =cJSON_CreateArray();
    for(int i = 1; i <= extdev_num; i++)
    {
        char  extdev_sn[HLINK_SN_LEN_MAX]= {0};
        snprintf(extdev_sn, HLINK_SN_LEN_MAX - 1, "%s-%03d", MCU_DEVICE_SN, i);
        item_devinfo = cJSON_CreateObject();
        item_devinfo_location = cJSON_CreateObject();
        if(item_devinfo==NULL ||item_devinfo_location==NULL) 
		{
			omip_printf(OMIP_ERROR,"[%s:%d]cJSON_CreateObject failed!\r\n",__FUNCTION__,__LINE__);
			goto failed_exit;
		}
        cJSON_AddStringToObject(item_devinfo, "sn", extdev_sn);
        cJSON_AddStringToObject(item_devinfo, "model", "light-xxx");
        cJSON_AddStringToObject(item_devinfo, "devType", "light");
        cJSON_AddStringToObject(item_devinfo, "manu", "minghaotian");
        cJSON_AddStringToObject(item_devinfo, "name", "xxxx");
        cJSON_AddStringToObject(item_devinfo, "desc", "light in J12A05");
        cJSON_AddStringToObject(item_devinfo, "mac", "");
        cJSON_AddStringToObject(item_devinfo, "hiv", (char*)g_hlink_info.hiv);
        cJSON_AddStringToObject(item_devinfo, "fwv", "10.01");
        cJSON_AddStringToObject(item_devinfo, "hwv", "VER.C");
        cJSON_AddStringToObject(item_devinfo, "swv", "V100R001C01B010");
        if(strcmp((char*)g_hlink_info.fwv,"WiFi.ailian")==0)		cJSON_AddStringToObject(item_devinfo,"protType","WiFi");
        else if(strcmp((char*)g_hlink_info.fwv,"PLC.huawei")==0)	cJSON_AddStringToObject(item_devinfo,"protType","PLC");
        else														cJSON_AddStringToObject(item_devinfo,"protType","ETH");
        cJSON_AddStringToObject(item_devinfo, "status", "online");
        cJSON_AddStringToObject(item_devinfo_location, "region", "�й���");
        cJSON_AddStringToObject(item_devinfo_location, "country", "�й�");
        cJSON_AddStringToObject(item_devinfo_location, "provice", "�㶫ʡ");
        cJSON_AddStringToObject(item_devinfo_location, "city", "������");
        cJSON_AddStringToObject(item_devinfo_location, "campus", "����");
        cJSON_AddStringToObject(item_devinfo_location, "building", "J1");
        cJSON_AddStringToObject(item_devinfo_location, "room", "1A03");
        cJSON_AddStringToObject(item_devinfo_location, "coordinate", "���ȣ�ά��");
        cJSON_AddItemToObject(item_devinfo, "location", item_devinfo_location);
        cJSON_AddItemToArray(item_devinfo_array, item_devinfo);
    }
    cJSON_AddItemToObject(root, "devInfos", item_devinfo_array);
    char* update_extdev_char =cJSON_PrintUnformatted(root);
    if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_JSON, HLINK_CMD_EXTDEV_UPDATE, (uint8_t *)update_extdev_char, strlen(update_extdev_char)+1) != OMIP_OK)
        omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
    omip_free(update_extdev_char);
    cJSON_Delete(root);
    return;
failed_exit:
    if (item_devinfo)			cJSON_Delete(item_devinfo);
    if (item_devinfo_location)	cJSON_Delete(item_devinfo_location);
    if (item_devinfo_array)		cJSON_Delete(item_devinfo_array);
    if (root)					cJSON_Delete(root);
}

void recv_add_extdev_rsp(uint8_t ct, uint8_t* data, int len)
{
    (void)len;
    if(ct ==OMIP_CONTENT_FORMAT_JSON)
    {
        cJSON* root =cJSON_Parse((char*) data);
        if(root ==NULL) {omip_printf(OMIP_INFO,"[%s:%d]invalid JSON format.\r\n",__FUNCTION__,__LINE__); return;}
        char* add_extdev_rsp = cJSON_PrintUnformatted(root);
        omip_printf(OMIP_INFO,"[%s:%d]received add_extdev_rsp:%s\r\n",__FUNCTION__,__LINE__,add_extdev_rsp);
        omip_free(add_extdev_rsp);
        cJSON_Delete(root);
    }
    else {omip_printf(OMIP_INFO,"[%s:%d]not support ct[%d] yet.\r\n",__FUNCTION__,__LINE__,ct);}
}

void recv_update_extdev_rsp(uint8_t ct, uint8_t* data, int len)
{
    (void)len;
    if(ct== OMIP_CONTENT_FORMAT_JSON)
    {
        cJSON* root =cJSON_Parse((char*) data);
        if(root ==NULL) {omip_printf(OMIP_INFO,"[%s:%d]invalid JSON format.\r\n",__FUNCTION__,__LINE__); return;}
        char* update_extdev_rsp = cJSON_PrintUnformatted(root);
        omip_printf(OMIP_INFO,"[%s:%d]received update_extdev_rsp:%s\r\n",__FUNCTION__,__LINE__,update_extdev_rsp);
        omip_free(update_extdev_rsp);
        cJSON_Delete(root);
    }
    else {omip_printf(OMIP_INFO,"[%s:%d]not support ct[%d] yet.\r\n",__FUNCTION__,__LINE__,ct);}
}

int srv_cmd_rsp_vavstatus(int mid)
{
	cJSON* root = cJSON_CreateObject();
	cJSON_AddStringToObject(root, "msgType", "terminalRsp");
	cJSON_AddNumberToObject(root, "mid", mid);
	cJSON_AddNumberToObject(root, "errorcode", 0);
	
	cJSON* item_body = cJSON_CreateObject();
	cJSON* item = cJSON_CreateObject();
	cJSON_AddItemToObject(root, "body", item_body);
	
	cJSON_AddItemToObject(item_body, "pannel", item);
	cJSON_AddNumberToObject(item, "status", (int)vav_get_panel_status());
	cJSON_AddNumberToObject(item, "settemp", (int)vav_get_panel_set_temp());
	cJSON_AddNumberToObject(item, "envtemp", (int)vav_get_panel_env_temp());

	item = cJSON_CreateObject();
	cJSON_AddItemToObject(item_body, "vav-inter", item);
	cJSON_AddNumberToObject(item, "degree", (int)vav_get_valve_degree());
	cJSON_AddNumberToObject(item, "pressure", (int)vav_get_pressure());

	item = cJSON_CreateObject();
	cJSON_AddItemToObject(item_body, "sum-status", item);
	cJSON_AddNumberToObject(item, "degree", (int)vav_get_sum_degree());
	cJSON_AddNumberToObject(item, "count", (int)vav_get_sum_count());

	char* srvcmd_rsp = cJSON_PrintUnformatted(root);
    uint16_t srvcmd_rsp_len = (uint16_t)strlen(srvcmd_rsp);
    if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_JSON, HLINK_CMD_SRV_CMD_RSP, (uint8_t *)srvcmd_rsp, srvcmd_rsp_len) != OMIP_OK)
        omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
    omip_free(srvcmd_rsp);
    cJSON_Delete(root);
	return 0;
}

int srv_cmd_rsp_debug(cJSON* srv_cmd, int mid)
{
	cJSON* body = cJSON_GetObjectItem(srv_cmd, "body");
	char * module_s = GET_JSON_ITEM(body, "module", valuestring, NULL);
	int  level = GET_JSON_ITEM(body, "level", valueint, 0);
	int module = app_log_module_str2enmu(module_s);
	if(module >= APP_LOG_MODULE_MAX || level >= APP_LEVEL_MAX) {
		OMIP_LOG_ERROR("module(%d):%s, level:%d",module, module_s, level);
		return -1;
	}
	if(APP_LOG_OMIP == module) {
		level = OMIP_DEBUG - level;
		omip_set_log_level(level);
		return 0;
	}
	if(APP_LOG_CENGINE == module) {
		cengine_set_log_level(level);
	}
	return 0;
}

int srv_cmd_rsp_flash(cJSON* srv_cmd, int mid)
{
	int ret = 0;
	cJSON* body = cJSON_GetObjectItem(srv_cmd, "body");
	char * option = GET_JSON_ITEM(body, "option", valuestring, NULL);
	if(0 == strcasecmp(option, "test")) {
		OMIP_LOG_INFO("Flash zone test");
		ret = flash_rw_zone_test();
	}
	else if(0 == strcasecmp(option, "erase")) {
		int  zone_id = GET_JSON_ITEM(body, "zone", valueint, 0);
		OMIP_LOG_INFO("Flash erase zone(%d)", zone_id);
		ret = flash_erase_zone(zone_id);
	}
	return ret;
}


int srv_cmd_rsp_write_property(cJSON* srv_cmd, int mid)
{
	cJSON* paras = cJSON_GetObjectItem(srv_cmd, "paras");
	if(NULL == paras) {
		return -1;
	}
	char *  objectIdentifier = GET_JSON_ITEM(paras, "objectIdentifier", valuestring, NULL);
	if(NULL == objectIdentifier) {
		return -1;
	}
	int obj_id = 0;
	sscanf(objectIdentifier, "%x", &obj_id);
	int priority = GET_JSON_ITEM(paras, "priority", valueint, 16);
	int arr_index = GET_JSON_ITEM(paras, "propertyArrayIndex", valueint, 16);
	if (0 == priority){
		vav_remove_priority(obj_id, arr_index);
	} else {
		cJSON* propertyValue = cJSON_GetObjectItem(paras, "propertyValue");
		if(NULL == propertyValue) {
			return -1;
		}
		double value = GET_JSON_ITEM(propertyValue, "realValue", valuedouble, -1);
		if(-1 == value) {
			return -1;
		}
		vav_set_msg_to_priority(obj_id, value, priority);
	}
	
	return 0;
}

cJSON *make_read_property_root_rsp(int mid)
{
	cJSON* root = cJSON_CreateObject();
	cJSON_AddStringToObject(root, "msgType", "terminalRsp");
	cJSON_AddNumberToObject(root, "mid", mid);
	cJSON_AddNumberToObject(root, "errorcode", 0);
	cJSON_AddStringToObject(root, "nodeId", g_mcu_sn);
	return root;
}

cJSON * make_read_property_body_rsp(char * obj, int value, int flag)
{
	cJSON* arr_item = cJSON_CreateObject();
	cJSON_AddStringToObject(arr_item, "objectIdentifier", obj);
	cJSON* listOfResults = cJSON_CreateArray();
	cJSON_AddItemToObject(arr_item, "listOfResults", listOfResults);
	
	cJSON* listOfResults_item = cJSON_CreateObject();
	cJSON_AddItemToArray(listOfResults, listOfResults_item);
	
	cJSON_AddNumberToObject(listOfResults_item, "propertyArrayIndex", 1);
	cJSON_AddStringToObject(listOfResults_item, "propertyIdentifier", "present-value");

	cJSON* readResult = cJSON_CreateObject();
	cJSON_AddItemToObject(listOfResults_item, "readResult", readResult);

	if(flag) {
		cJSON* propertyValue = cJSON_CreateObject();
		cJSON_AddItemToObject(readResult, "propertyValue", propertyValue);
		cJSON_AddNumberToObject(propertyValue, "realValue", value);
	}
	else {
		cJSON* propertyAccessError = cJSON_CreateObject();
		cJSON_AddItemToObject(readResult, "propertyAccessError", propertyAccessError);
		cJSON_AddStringToObject(propertyAccessError, "error-class", "object");
		cJSON_AddStringToObject(propertyAccessError, "error-code", "unknown-object");
	}

	return arr_item;
}


int srv_cmd_rsp_read_property(cJSON* srv_cmd, int mid, uint16_t cmd)
{
	double value;
	int priority;
	char stype[16];
	int ret = 0;
	cJSON* paras = cJSON_GetObjectItem(srv_cmd, "paras");
	if(NULL == paras) {
		return -1;
	}
	cJSON *	listOfReadAccessSpecs = cJSON_GetObjectItem(paras, "listOfReadAccessSpecs");
	if(NULL == listOfReadAccessSpecs) {
		return -1;
	}
	cJSON * root = make_read_property_root_rsp(mid);
	int arr_size = cJSON_GetArraySize(listOfReadAccessSpecs);
	cJSON* body = cJSON_CreateObject();
	cJSON* array = cJSON_CreateArray();
	cJSON_AddItemToObject(root, "body", body);
	cJSON_AddItemToObject(body, "listOfReadAccessResults", array);
	
	OMIP_LOG_DEBUG("read property size:%d", arr_size);
	for (int i = 0; i < arr_size; i++)
	{
		cJSON * arr = cJSON_GetArrayItem(listOfReadAccessSpecs, i);
		char *  objectIdentifier = GET_JSON_ITEM(arr, "objectIdentifier", valuestring, NULL);
		if(NULL == objectIdentifier) {
			continue;
		}
		int obj_id = 0;
		sscanf(objectIdentifier, "%x", &obj_id);
		OMIP_LOG_DEBUG("obj_id:%08x", obj_id);
		memset(stype, 0, sizeof(stype));
		ret = vav_get_msg_to_priority(obj_id, &value, &priority, stype);
		if(0 != ret) {
			OMIP_LOG_DEBUG("unknown-object");
		}
		else {
			OMIP_LOG_DEBUG("read point obj_id:%s value:%d, priority:%d, stype:%s", 
				objectIdentifier, (int)value, priority, stype);
		}
		cJSON* item=  make_read_property_body_rsp(objectIdentifier, (int)value, ret == 0 ? 1 : 0);
		cJSON_AddItemToArray(array, item);
	}
	char* srvcmd_rsp = cJSON_PrintUnformatted(root);
	uint16_t srvcmd_rsp_len = (uint16_t)strlen(srvcmd_rsp);
	OMIP_LOG_INFO("read_property json:%s", srvcmd_rsp);
    if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_JSON, cmd, (uint8_t *)srvcmd_rsp, srvcmd_rsp_len) != OMIP_OK){
        	omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
	}
    omip_free(srvcmd_rsp);
    cJSON_Delete(root);
	return 0;
}

void process_srv_cmd(uint8_t ct, uint8_t* data, int len, uint16_t cmd)
{
	cJSON* srv_cmd =NULL;
	uint8_t bReboot =0, bRstWifi =0;
	int ret = 0;
    uint16_t rsp_cmd = HLINK_CMD_SRV_CMD_RSP;
    if(cmd == HLINK_CMD_SRV_TRACE_CMD) {
        rsp_cmd = HLINK_CMD_SRV_TRACE_CMD_RSP;
    }
    switch (ct)
	{
        case OMIP_CONTENT_FORMAT_JSON:
        {
            srv_cmd =cJSON_Parse((char*)data);
            if(srv_cmd ==NULL) {omip_printf(OMIP_INFO,"[%s:%d]invalid JSON format.\r\n",__FUNCTION__,__LINE__); return;}
			char *cmd =GET_JSON_ITEM(srv_cmd, "cmd", valuestring, NULL);
			int   mid =GET_JSON_ITEM(srv_cmd, "mid", valueint, -1);
			if(0 ==strcasecmp(cmd,"eraseflash"))
			{
				g_flash_sn = file_addr_init("bksn",FILE_BL_BKSN_ADDR, FILE_BL_BKSN_SIZE);
				g_flash_sn->buff = (char *)malloc(sizeof(uint8_t)*g_flash_sn->size);
				read_data_from_file(g_flash_sn);
				omip_printf(OMIP_ERROR,"[%s:%d]begin erase W25QXX flash,sn:%s!\r\n",__FUNCTION__,__LINE__,g_flash_sn->buff);
				W25QXX_Erase_Chip();
				omip_printf(OMIP_ERROR,"[%s:%d]erase W25QXX flash success!\r\n",__FUNCTION__,__LINE__);
				save_data_to_file(g_flash_sn);
				omip_printf(OMIP_ERROR,"[%s:%d]write sn(%s) success!\r\n",__FUNCTION__,__LINE__,g_flash_sn->buff);
				free_w25flash_t(&g_flash_sn);
				bReboot = 1;
			}
			else if(0 ==strcasecmp(cmd,"writesn"))
			{
				cJSON* body = cJSON_GetObjectItem(srv_cmd, "body");
				char *vav_sn = GET_JSON_ITEM(body, "sn", valuestring, NULL);
				if(vav_sn && strlen(vav_sn)<64)
				{
					w25flash_t *bk_flash_sn= file_addr_init("bksn",FILE_BL_BKSN_ADDR,FILE_BL_BKSN_SIZE);
					bk_flash_sn->buff = (char *)malloc(sizeof(uint8_t)*bk_flash_sn->size);
					strcpy(bk_flash_sn->buff,vav_sn);
					save_data_to_file(bk_flash_sn);
					free_w25flash_t(&bk_flash_sn);
					g_flash_sn = file_addr_init("sn",FILE_BL_SN_ADDR, FILE_BL_SN_SIZE);
					g_flash_sn->buff = (char *)malloc(sizeof(uint8_t)*g_flash_sn->size);
					strcpy(g_flash_sn->buff,vav_sn);
					save_data_to_file(g_flash_sn);
					omip_printf(OMIP_ERROR,"[%s:%d]write sn(%s) success!\r\n",__FUNCTION__,__LINE__,g_flash_sn->buff);
					free_w25flash_t(&g_flash_sn);
					bReboot = 1;
				}
			}
			else if(0 ==strcasecmp(cmd,"eraseflow"))
			{
				int flag =0x00, length =0x00;
			    W25QXX_Read((uint8_t *)&flag,0x100400,2);
				omip_printf(OMIP_ERROR,"[%s:%d]eraseflow,local flag:%x\r\n",__FUNCTION__,__LINE__,flag);
				flag = 0x00;
				W25QXX_Write((uint8_t *)&flag,0x100400,2);
			    W25QXX_Read((uint8_t *)&length,0x100402,4);
				length = 0x00;
				W25QXX_Write((uint8_t *)&flag,0x100402,2);
				bReboot =1;
			}
			else if(0 ==strcasecmp(cmd,"vavstatus"))
			{
				srv_cmd_rsp_vavstatus(mid);
				break;
			}
			else if(0 ==strcasecmp(cmd,"getmeminfo"))
			{
				LOS_MEM_STATUS sMemInfo = {0};
				cJSON* root = cJSON_CreateObject();
				LOS_MemStatisticsGet(OS_SYS_MEM_ADDR, &sMemInfo);
				omip_printf(OMIP_INFO,"flash[total:%u,used:%u,free:%u]\r\n", sMemInfo.totalSize, sMemInfo.usedSize,sMemInfo.freeSize);
				cJSON_AddStringToObject(root, "msgType", "terminalRsp");
				cJSON_AddNumberToObject(root, "mid", mid);
				cJSON_AddNumberToObject(root, "errorcode", 0);
				cJSON* item_body = cJSON_CreateObject();
				cJSON* item = cJSON_CreateObject();
				cJSON_AddItemToObject(root, "body", item_body);
				cJSON_AddItemToObject(item_body, "flash", item);
				cJSON_AddNumberToObject(item, "total", sMemInfo.totalSize);
				cJSON_AddNumberToObject(item, "used", sMemInfo.usedSize);
				cJSON_AddNumberToObject(item, "free", sMemInfo.freeSize);
				LOS_MemStatisticsGet(Bank5_SDRAM_ADDR,&sMemInfo);
				omip_printf(OMIP_INFO,"extflash[total:%u,used:%u,free:%u]\r\n", sMemInfo.totalSize, sMemInfo.usedSize,sMemInfo.freeSize);
				item = cJSON_CreateObject();
				cJSON_AddItemToObject(item_body, "extflash", item);
				cJSON_AddNumberToObject(item, "total", sMemInfo.totalSize);
				cJSON_AddNumberToObject(item, "used", sMemInfo.usedSize);
				cJSON_AddNumberToObject(item, "free", sMemInfo.freeSize);
	            char* srvcmd_rsp = cJSON_PrintUnformatted(root);
	            uint16_t srvcmd_rsp_len = (uint16_t)strlen(srvcmd_rsp);
	            if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_JSON, HLINK_CMD_SRV_CMD_RSP, (uint8_t *)srvcmd_rsp, srvcmd_rsp_len) != OMIP_OK)
	                omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
	            omip_free(srvcmd_rsp);
	            cJSON_Delete(root);
				break;	
			}
			else if(0 ==strcasecmp(cmd,"debug"))
			{
				srv_cmd_rsp_debug(srv_cmd, mid);
			}
			else if(0 ==strcasecmp(cmd,"writeProperty"))
			{
				ret = srv_cmd_rsp_write_property(srv_cmd, mid);
			}
			else if(0 ==strcasecmp(cmd,"readPropertyMultiple"))
			{
				ret = srv_cmd_rsp_read_property(srv_cmd, mid, rsp_cmd);
				if(0 == ret) {
					break;
				}
			}
			else if(0 ==strcasecmp(cmd,"flash")) {
				ret = srv_cmd_rsp_flash(srv_cmd, mid);
			}
			else if(0 ==strcasecmp(cmd,"rstwifi"))
			{
				bRstWifi = 1;
			}
			else if(0 ==strcasecmp(cmd,"reboot"))
			{
				bReboot = 1;
			}
            omip_printf(OMIP_INFO,"[%s:%d]receive srvcmd_mid=%d\r\n",__FUNCTION__,__LINE__,mid);
            cJSON* root =cJSON_CreateObject();
            cJSON_AddStringToObject(root, "msgType", "terminalRsp");
            cJSON_AddNumberToObject(root, "mid", mid);
            cJSON_AddNumberToObject(root, "errorcode", ret);
            cJSON* item_body = cJSON_CreateObject();
            cJSON* item_bacnet = cJSON_CreateObject();
            cJSON* item_readProperty = cJSON_CreateObject();
            cJSON_AddStringToObject(item_readProperty, "objectIdentifier", "00000001");
            cJSON_AddStringToObject(item_readProperty, "propertyIdentifier", "present-value");
            cJSON* item_propertyValue = cJSON_CreateObject();
            cJSON_AddNumberToObject(item_propertyValue, "intValue", 1);
            cJSON_AddItemToObject(root, "body", item_body);
            cJSON_AddItemToObject(item_body, "bacnet", item_bacnet);
            cJSON_AddItemToObject(item_bacnet, "readProperty", item_readProperty);
            cJSON_AddItemToObject(item_readProperty, "propertyValue", item_propertyValue);
            char* srvcmd_rsp = cJSON_PrintUnformatted(root);
            uint16_t srvcmd_rsp_len = (uint16_t)strlen(srvcmd_rsp);
            if(omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_JSON, rsp_cmd, (uint8_t *)srvcmd_rsp, srvcmd_rsp_len) != OMIP_OK)
                omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
			if(bReboot)		system_reset_delay();
			if(bRstWifi)	wifi_reset();
            omip_free(srvcmd_rsp);
            cJSON_Delete(root);
            break;
        }
        case OMIP_CONTENT_FORMAT_ASN1_DER:
        {
        	char asn1_der_rsp_data[] ={0X30,0X21,0X80,0X01,0X02,0X81,0X05,0X00,0XCC,0X89,0X30,0X8C,0X82,0X01,0X00,0XA3,0X12,0XA0,0X10,0XAC,0X0E,0X80,0X04,0X00,0X00,0X00,0X01,0X81,0X01,0X55,0XA3,0X03,0X82,0X01,0X01};
            omip_printf(OMIP_INFO,"[%s:%d]CONTENT_FORMAT_ASN1_DER,len:%d\r\n",__FUNCTION__,__LINE__,sizeof(asn1_der_rsp_data));
            if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_ASN1_DER, rsp_cmd,(uint8_t *)asn1_der_rsp_data,sizeof(asn1_der_rsp_data))!=OMIP_OK)
                omip_printf(OMIP_ERROR,"[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
            break;
        }
        case OMIP_CONTENT_FORMAT_ASN1_UPER:
        {
			process_point_rw(OMIP_VC_DEFAULT0,(char *)data ,len, rsp_cmd);
            break;
        }
        default:
        {
            omip_printf(OMIP_INFO,"[%s:%d]not support ct[%d] yet.\r\n",__FUNCTION__,__LINE__,ct);
            break;
        }
    }
	if(srv_cmd) cJSON_Delete(srv_cmd);
}

int mcu_check_auth(uint8_t vc) //检测蓝牙认证是否通过
{
	struct omip_context_tag *context =omip_get_context();
	app_session *app_s =(app_session *)context->sock[vc].app_s;
	if(app_s->auth_code ==HLINK_APP_AUTH_PASS) return 1; //蓝牙认证已经通过
	else									   return 0; //蓝牙认证还没通过
}

void mcu_response_to_ble(cJSON *json,int ts_cmd) //回复蓝牙数据
{
	omip_transaction send_ts = {0};
	send_ts.vc = OMIP_VC_CHANNEL6;
	send_ts.relay_flag = 0;
	send_ts.relay_vc = 0;
	send_ts.ctf = OMIP_CONTENT_FORMAT_JSON;
	send_ts.timeout = OMIP_SEND_DEFAULT;  //default 2s
	send_ts.ext_io_flag = OMIP_ENCODE_EXT;//when send to BLE, must chose this
	if (NULL ==json) {omip_printf(OMIP_ERROR,"Error before: [%s]\r\n",cJSON_GetErrorPtr()); return;}
	cJSON *json_mid = cJSON_GetObjectItem(json, "mid");
	int mid = json_mid->valueint;
	omip_printf(OMIP_INFO,"mid :%d \r\n",mid);

	//char *srv = GET_JSON_ITEM(json, "srv", valuestring, NULL);
	//char *cmd = GET_JSON_ITEM(json, "cmd", valuestring, NULL);
	cJSON *paras = cJSON_GetObjectItem(json, "paras");
	cJSON *retJson = cJSON_CreateObject();
	cJSON_AddItemToObject(retJson, "mid", cJSON_CreateNumber(mid));
	cJSON_AddItemToObject(retJson, "errcode", cJSON_CreateNumber(0));
	cJSON_AddStringToObject(retJson, "status", "reserve");
	cJSON_AddItemToObject(retJson, "paras",paras);
	char *retData = cJSON_PrintUnformatted(retJson);
	send_ts.data = (unsigned char *)retData;
	send_ts.len = strlen(retData);
	send_ts.cmd = ts_cmd;
	omip_send(&send_ts);
	omip_printf(OMIP_INFO,"[%s:%d]returned result for app:%s,mid:%d.\r\n",__FUNCTION__,__LINE__,retData, mid);
	cJSON_Delete(retJson);
	omip_free(retData);
}

#define MOCK_SECURITY 0
unsigned int recv_req_time;
unsigned int send_rsp_time;
int mcu_recv_security_connect_req(unsigned char vc, unsigned char *data, unsigned int len) //蓝牙登录请求
{
    struct omip_context_tag *context =omip_get_context();
    omip_transaction send_ts = {0};
    hlink_app_security_req req;
#if MOCK_SECURITY
    static int mock = 0;
    cJSON *root =NULL, *sub =NULL;
    char challenge[32+1] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    int need_free_sub = 0;
#endif    
    if(vc >= OMIP_VC_CHANNEL_TOTAL) return OMIP_ERROR_UNKNOWN;
    recv_req_time = osal_sys_time();
    if(context->sock[vc].support_auth !=1)
    {
        omip_printf(OMIP_INFO,"this channel cannot support security auth,vc:%d,auth:%d\r\n",vc,context->sock[vc].support_auth);
        return OMIP_ERROR_UNKNOWN;
    }
#if MOCK_SECURITY
    root =cJSON_CreateObject();
    sub =cJSON_CreateObject();
#endif
    memset_s(&req, sizeof(req),0,sizeof(req));
    if(len < OMIP_USER_RECV_BUF) data[len] = '\0';
    cJSON *connect_cmd =cJSON_Parse((char*) data);
    if(connect_cmd == NULL)
    {
    #if MOCK_SECURITY
        cJSON_Delete(root);
        cJSON_Delete(sub);
    #endif
        omip_printf(OMIP_INFO,"received connect_cmd is not invalid JSON format.\r\n");
        return OMIP_ERROR_UNKNOWN;
    }
    char *operate = GET_JSON_ITEM(connect_cmd, "cmd", valuestring, "");
    int mid = GET_JSON_ITEM(connect_cmd, "mid", valueint, -1);
#if MOCK_SECURITY
    omip_printf(OMIP_INFO,"will mock response\r\n");
    cJSON_AddNumberToObject(root, "mid", mid);
    cJSON_AddStringToObject(root, "status", "reserve");
#endif
    req.mid = mid;
	omip_printf(OMIP_INFO,"[%s:%d]operate: %s\r\n",__FUNCTION__,__LINE__,operate);
    if(strcmp(operate,HLINK_SHOWPWD_STRING) == 0) {
        req.operate = HLINK_APP_LOGIN;
        cJSON *paras = cJSON_GetObjectItem(connect_cmd, "paras");
        if(paras != NULL)
        {
            char *s_pwd_sha256 = GET_JSON_ITEM(paras, "pwd", valuestring, "");
            memcpy_s(req.u.s_pwd_sha256, sizeof(req.u.s_pwd_sha256)-1, s_pwd_sha256, strlen(s_pwd_sha256));
        #if MOCK_SECURITY
            omip_printf(OMIP_INFO,"success\r\n");
            cJSON_AddNumberToObject(root, "errcode", 0);
            cJSON_AddItemToObject(root, "paras", sub);
            app_session *app_s = (app_session *)context->sock[vc].app_s;
            app_s->auth_code = HLINK_APP_AUTH_PASS;
        #endif
            //omip_printf(OMIP_ERROR,"this is root :%s \r\n",cJSON_PrintUnformatted(root));
        }
        else
        {
            omip_printf(OMIP_INFO,"login but no paras!!\r\n");
            cJSON_Delete(connect_cmd);
        #if MOCK_SECURITY
            cJSON_Delete(root);
            cJSON_Delete(sub);
        #endif
            return -1;
        }
    }
    else if(strcmp(operate, HLINK_SETPWD_STRING) == 0) {
        cJSON *paras = cJSON_GetObjectItem(connect_cmd, "paras");
        if(paras != NULL)
        {
            char *s_newpwd = GET_JSON_ITEM(paras, "newPwd", valuestring, "");
            char *s_oldpwd = GET_JSON_ITEM(paras, "oldPwd", valuestring, "");
            if(strcmp(s_oldpwd, "") == 0) //first set pwd
            {
                omip_printf(OMIP_INFO,"set passwd\r\n");
                req.operate = HLINK_APP_SET_PWD;
                memcpy_s(req.u.s_pwd, sizeof(req.u.s_pwd)-1, s_newpwd, strlen(s_newpwd));
            #if MOCK_SECURITY
                cJSON_AddNumberToObject(root, "errcode", 0);     
            #endif
            }
            else // modify pwd
            {
                omip_printf(OMIP_INFO,"modify passwd\r\n");
                req.operate = HLINK_APP_MODIFY_PWD;
                memcpy_s(req.u.s_set.old_pwd, sizeof(req.u.s_set.old_pwd)-1, s_oldpwd, strlen(s_oldpwd));
                memcpy_s(req.u.s_set.new_pwd, sizeof(req.u.s_set.new_pwd)-1, s_newpwd, strlen(s_newpwd));
            #if MOCK_SECURITY
                cJSON_AddNumberToObject(root, "errcode", 0);     
            #endif
            }
        #if MOCK_SECURITY
            need_free_sub = 1;
        #endif
        }
        else
        {
            cJSON_Delete(connect_cmd);
        #if MOCK_SECURITY
            cJSON_Delete(root);
            cJSON_Delete(sub);
        #endif
            return -1;
        }
    }
    else if(strcmp(operate, HLINK_DISCOVERY_STRING) == 0) {
        req.operate = HLINK_APP_DISCOVERY;
    #if MOCK_SECURITY
        if(mock == 0)
        {
            cJSON_AddNumberToObject(root, "errcode", 0);
            cJSON_AddStringToObject(sub, "operateCode", "setPwd");
            cJSON_AddItemToObject(root, "paras", sub);
            mock=1;
        }
        else
        {
            cJSON_AddNumberToObject(root, "errcode", 0);
            cJSON_AddStringToObject(sub, "operateCode", "showPwd");
            cJSON_AddStringToObject(sub, "challenge", challenge);
            cJSON_AddItemToObject(root, "paras", sub);
        }
    #endif
    }
    else {
        omip_printf(OMIP_INFO,"[%s:%d]unkown app operate:%s\r\n",__FUNCTION__,__LINE__,operate);
        cJSON_Delete(connect_cmd);
    #if MOCK_SECURITY
        cJSON_Delete(root);
        cJSON_Delete(sub);
    #endif
        return -1;
    }
    cJSON_Delete(connect_cmd);
#if !MOCK_SECURITY    
    send_ts.vc = OMIP_VC_CHANNEL4;
    send_ts.relay_flag = 0;
    send_ts.relay_vc = 0;
    send_ts.ctf = OMIP_CONTENT_FORMAT_BINARY;
    send_ts.cmd = HLINK_CMD_CONNECT_AUTH_REQ;
    send_ts.data = (unsigned char *)&req; //pay load data
    send_ts.len = sizeof(req);
    send_ts.timeout = OMIP_SEND_DEFAULT;  //default 2s
    send_ts.ext_io_flag = OMIP_ENCODE_DEFAULT;
    return omip_send(&send_ts); //回复蓝牙
#else
    char *result = cJSON_PrintUnformatted(root);
    if(result ==NULL) {cJSON_Delete(root); if(need_free_sub) cJSON_Delete(sub); return -1;}
    omip_printf(OMIP_INFO,"mock result:%s\r\n",result);
    send_ts.vc = OMIP_VC_CHANNEL6;
    send_ts.relay_flag = 0;
    send_ts.relay_vc = 0;
    send_ts.ctf = OMIP_CONTENT_FORMAT_BINARY;
    send_ts.cmd = HLINK_CMD_CONNECT_RSP;
    send_ts.data = (unsigned char *)result;
    send_ts.len = strlen(result);
    send_ts.timeout = OMIP_SEND_DEFAULT;   //default 2s
    send_ts.ext_io_flag = OMIP_ENCODE_EXT; //when send to BLE, must chose this
    int iret =omip_send(&send_ts); //回复蓝牙
    omip_free(result);
    cJSON_Delete(root);
    if(need_free_sub) cJSON_Delete(sub);
	return iret;
#endif
}

int mcu_recv_security_connect_auth_rsp(unsigned char vc,unsigned char *data,unsigned int len)
{
    hlink_app_security_rsp *rsp = (hlink_app_security_rsp *)data;
    struct omip_context_tag *context = omip_get_context();
    app_session *app_s =NULL;
    if(vc >= OMIP_VC_CHANNEL_TOTAL)	return OMIP_ERROR_UNKNOWN;
    omip_printf(OMIP_INFO,"[%s:%d]auth msg.vc:%d, operate:%d,retcode:%d,mid:%d!\r\n",__FUNCTION__,__LINE__,vc,rsp->operate,rsp->result,rsp->mid);
    cJSON *root =cJSON_CreateObject(),*sub =cJSON_CreateObject();
    cJSON_AddNumberToObject(root, "mid", rsp->mid);
    cJSON_AddStringToObject(root, "status", "reserve");    
    switch(rsp->operate)
    {
    case HLINK_APP_DISCOVERY:
        if(rsp->result == HLINK_APP_PWD_NOT_EXIST)
        {
            cJSON_AddNumberToObject(root, "errcode", 0);
            cJSON_AddStringToObject(sub, "operateCode", "setPwd");
            cJSON_AddItemToObject(root, "paras", sub);
			sub =NULL;
        }
        else if(rsp->result == HLINK_APP_PWD_EXIST)
        {
            cJSON_AddNumberToObject(root, "errcode", 0);
            cJSON_AddStringToObject(sub, "operateCode", "showPwd");
            cJSON_AddStringToObject(sub, "challenge", rsp->challenge);
            cJSON_AddItemToObject(root, "paras", sub);
			sub =NULL;
        }
        else
        {
            cJSON_AddNumberToObject(root, "errcode", rsp->result);
        }
        break;
    case HLINK_APP_SET_PWD:
    case HLINK_APP_MODIFY_PWD:
        if(rsp->result == HLINK_OK){
			cJSON_AddNumberToObject(root, "errcode", 0);
        }
        else {
			cJSON_AddNumberToObject(root, "errcode", rsp->result);
        }
        break;
    case HLINK_APP_LOGIN:
        cJSON_AddNumberToObject(root, "errcode", rsp->result);
        app_s =(app_session *)context->sock[vc].app_s;
        if(rsp->result== HLINK_OK) {
			app_s->auth_code =HLINK_APP_AUTH_PASS;
        }
        else {
			app_s->auth_code =HLINK_APP_AUTH_FAILED;
        }
        break;
    default:
        cJSON_AddNumberToObject(root, "errcode", rsp->result);
        break;
    }
    char *result = cJSON_PrintUnformatted(root);
    if(result ==NULL) {cJSON_Delete(root); if(sub) cJSON_Delete(sub); return -1;}
    omip_printf(OMIP_INFO,"[%s:%d]result:%s\r\n",__FUNCTION__,__LINE__,result);
    omip_transaction send_ts = {0};
    send_ts.vc = OMIP_VC_CHANNEL6;
    send_ts.relay_flag = 0;
    send_ts.relay_vc = 0;
    send_ts.ctf = OMIP_CONTENT_FORMAT_JSON;
    send_ts.cmd = HLINK_CMD_CONNECT_RSP;
    send_ts.data = (unsigned char *)result;
    send_ts.len = strlen(result);
    send_ts.timeout = OMIP_SEND_DEFAULT;  	//default 2s
    send_ts.ext_io_flag = OMIP_ENCODE_EXT;	//when send to BLE, must chose this
    omip_send(&send_ts);
    omip_free(result);
    cJSON_Delete(root);
    if(sub) cJSON_Delete(sub);
    return 0;
}

int mcu_recv_ble_notify(unsigned char vc,unsigned char *data,unsigned int len)
{
    unsigned char ble_app_status = *data;
    struct omip_context_tag *context = omip_get_context();
    app_session *app_s;

    if(context->sock[vc].support_auth == 1)
    {
        app_s = context->sock[vc].app_s;
        if(app_s == NULL)
        {
            return -1;
        }

        if(ble_app_status == MCU_BLE_APP_OFFLINE)
        {
            app_s->auth_code = HLINK_APP_AUTH_CLOSED;
            /* if app offline and mcu log upload switch is on, then close off */
            if (hlink_get_log_switch(HLINK_UPLOAD_APP) == HLINK_LOG_UPLOAD_ON)
            {
                hlink_set_log_switch(HLINK_LOG_UPLOAD_OFF, HLINK_UPLOAD_APP);
            }
        }
        else if(ble_app_status == MCU_BLE_APP_ONLINE)
        {
            app_s->auth_code = HLINK_APP_AUTH_INIT;
        }
        else
        {
            return -1;
        }
    }
    if(len > 1)
    {
        omip_api_send(OMIP_VC_CHANNEL4, OMIP_CONTENT_FORMAT_BINARY,
 	                  HLINK_CMD_BLE_NOTIFY, data + 1, len - 1);
    }
    return 0;
}

int mcu_auth_app_msg(unsigned char vc, unsigned char *data, int len)
{
	int iRet =0;
    struct omip_context_tag *context = omip_get_context();
    cJSON *connect_cmd =cJSON_Parse((char*)data);
	if(connect_cmd ==NULL) {omip_printf(OMIP_INFO,"[%s:%d]invalid JSON format.\r\n",__FUNCTION__,__LINE__); return -1;}
    if(vc >= OMIP_VC_CHANNEL_TOTAL) {omip_printf(OMIP_ERROR,"vc(%d) is invalid\r\n",vc); return -1;}
    app_session *app_s = (app_session *)context->sock[vc].app_s;
    if(app_s->auth_code !=HLINK_APP_AUTH_PASS) iRet =-1;
	omip_printf(OMIP_INFO,"[%s:%d]app auth %s(%d)\r\n",__FUNCTION__,__LINE__,(iRet==-1?"failed":"success"),app_s->auth_code);
    cJSON_Delete(connect_cmd);
    return iRet;
}

int mcu_recv_set_module_config(unsigned char *data, int len)
{
    hlink_set_module_config_req req;
    cJSON *conf_root = cJSON_Parse((char*)data);
    if(conf_root ==NULL) {omip_printf(OMIP_INFO,"[%s:%d]invalid JSON format.\r\n",__FUNCTION__,__LINE__); return -1;}
	else				 {omip_printf(OMIP_INFO,"[%s:%d]config data: %s\r\n",__FUNCTION__,__LINE__,(char *)data);}
    memset_s(&req,sizeof(req),0,sizeof(req));
    req.mid = GET_JSON_ITEM(conf_root, "mid", valueint, -1);
    cJSON *paras = cJSON_GetObjectItem(conf_root, "paras");
    if(paras ==NULL) {omip_printf(OMIP_ERROR,"[%s:%d]get paras failed.\r\n",__FUNCTION__,__LINE__); cJSON_Delete(conf_root); return -1;}
    char *s_ssid = GET_JSON_ITEM(paras, "ssid", valuestring, "");
    char *s_pwd = GET_JSON_ITEM(paras, "pwd", valuestring, "");
    char *s_gwip = GET_JSON_ITEM(paras, "gwip", valuestring, "");
    char *s_gwport = GET_JSON_ITEM(paras, "gwport", valuestring, "");
    memcpy_s(req.conf.ssid, sizeof(req.conf.ssid)-1, s_ssid, strlen(s_ssid));
    memcpy_s(req.conf.pwd, sizeof(req.conf.pwd)-1, s_pwd, strlen(s_pwd));
    omip_printf(OMIP_INFO,"req.conf.ssid:%s\r\n",req.conf.ssid);
    omip_printf(OMIP_INFO,"req.conf.pwd:%s\r\n",req.conf.pwd);
    if(strlen(s_gwip) != 0) {
        req.conf.flag = 1;
        memcpy_s(req.conf.gatewayip, sizeof(req.conf.gatewayip)-1, s_gwip, strlen(s_gwip));
        req.conf.gatewayport = atoi(s_gwport);
        omip_printf(OMIP_INFO,"[%s:%d]gatewayip:%s,gatewayport:%d\r\n",__FUNCTION__,__LINE__,req.conf.gatewayip,req.conf.gatewayport);
    }
    omip_api_send(OMIP_VC_CHANNEL4,OMIP_CONTENT_FORMAT_BINARY,HLINK_CMD_SET_MODULE_CONF,(unsigned char *)&req,sizeof(req));
    cJSON_Delete(conf_root);
    return 0;
}

int mcu_recv_get_module_config(unsigned char *data, int len)
{
    hlink_get_module_config_req req;
    cJSON *conf_root =cJSON_Parse((char*)data);
    if(conf_root==NULL) {omip_printf(OMIP_ERROR,"[%s:%d]invalid JSON format.\r\n",__FUNCTION__,__LINE__); return -1;}
    else				{omip_printf(OMIP_INFO,"[%s:%d]config data: %s\r\n",__FUNCTION__,__LINE__,(char *)data);}
    memset_s(&req,sizeof(req),0,sizeof(req));
    req.mid = GET_JSON_ITEM(conf_root, "mid", valueint, -1);
    omip_api_send(OMIP_VC_CHANNEL4,OMIP_CONTENT_FORMAT_BINARY,HLINK_CMD_GET_MODULE_CONF,(unsigned char *)&req,sizeof(req));
    cJSON_Delete(conf_root);
    return 0;
}



int g_update_flag = 0;
static int g_beatheart_timeout = 0;
int cmd_connect_beatheart(uint8_t status)
{
	device_beatheart beatheart = {0};
	if(HLINK_ONLINE == status) {
		beatheart.seq = 0;
	}
	else {
		beatheart.seq = 1;
	}
	beatheart.status = status;
	beatheart.res = 0;
	g_beatheart_timeout++;
	int ret = omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_BINARY, 
		HLINK_CMD_CONNECT_BEATHEART, (uint8_t*)&beatheart, sizeof(device_beatheart));
    if(ret != OMIP_OK) {
        OMIP_LOG_ERROR("omip_api_send failed!\r\n");
		return ret;
    }
	OMIP_LOG_DEBUG("beatheart status:%d, seq:%d", beatheart.status, beatheart.seq);
	return OMIP_OK;
}

void get_cmd_connect_beatheart(uint8_t ct, uint8_t* data, int len)
{
	if(OMIP_CONTENT_FORMAT_BINARY != ct) {
		OMIP_LOG_ERROR("only support binary format");
		return;
	}
	if(len != sizeof(device_beatheart)) {
		OMIP_LOG_ERROR("format error , len[%d],expect len[%d]");
		return;
	}
	device_beatheart *beatheart = (device_beatheart *)data;
	g_beatheart_timeout = 0;
	OMIP_LOG_DEBUG("beatheart rsp status:%d, seq:%d, res:%d", beatheart->status, beatheart->seq, beatheart->res);
	
	return;
}

static void device_manager_rsp_channel6(unsigned short cmd, uint8_t* data, int len)
{
    omip_transaction send_ts = {0};
    send_ts.vc = OMIP_VC_CHANNEL6;
    send_ts.relay_flag = 0;
    send_ts.relay_vc = 0;
    send_ts.ctf = OMIP_CONTENT_FORMAT_JSON;
    send_ts.cmd = cmd;

    send_ts.data = (unsigned char *)data;
    send_ts.len = len;
    send_ts.timeout = OMIP_SEND_DEFAULT;  //default 2s
    send_ts.ext_io_flag = OMIP_ENCODE_EXT; //when send to BLE, must chose this
    if(omip_send(&send_ts) != OMIP_OK) {
        OMIP_LOG_ERROR("omip send failed, cmd[0x%x]\n", cmd);
    }
    return;
}

static void device_manager_rsp_channel4(unsigned short cmd, uint8_t* data, int len)
{
    int ret = omip_api_send(OMIP_VC_CHANNEL4, OMIP_CONTENT_FORMAT_JSON, cmd, data, len);
    if (ret != OMIP_OK) {
        omip_printf(OMIP_ERROR, "omip send cmd[0x%04x] to hlink failed\n", cmd);
    }
    return;
}

void device_manager_rsp_api_channel6(int mid, int err)
{
    char *result = NULL;
    cJSON *rsp = cJSON_CreateObject();
    if (rsp == NULL) {
        OMIP_LOG_ERROR("cjson creat object failed\n");
        return;
    }
    cJSON_AddNumberToObject(rsp, "mid", mid);
    cJSON_AddNumberToObject(rsp, "errcode", err);
    result = cJSON_PrintUnformatted(rsp);
    if (result == NULL) {
        cJSON_Delete(rsp);
        return;
    }
	
    device_manager_rsp_channel6(HLINK_CMD_DEVICE_MANAGER_RSP, (uint8_t*)result, strlen(result));
    omip_free(result);
    cJSON_Delete(rsp);
    return;
}

static int device_manager_debug_mcu_proc(cJSON *device_manager_info, hlink_log_upload_direction direction)
{
    if (device_manager_info == NULL) {
        return -1;
    }

    char *cmd = GET_JSON_ITEM(device_manager_info, "cmd", valuestring, "");
    if (strcmp(cmd, "upload_on") == 0) {
        hlink_set_log_switch(HLINK_LOG_UPLOAD_ON, direction);
    } else if (strcmp(cmd, "upload_off") == 0) {
        hlink_set_log_switch(HLINK_LOG_UPLOAD_OFF, direction);
    } else {
        return -1;
    }
    MCU_LOG(MCU_LOG_DEBUG_UPLOAD, "set mcu log %s successfully", cmd);

    return 0;
}

static void device_manager_debug_info_proc(cJSON *device_manager_info, uint8_t* data, int len)
{
    int ret = 0;
    int mid = GET_JSON_ITEM(device_manager_info, "mid", valueint, -1);
    cJSON *paras = cJSON_GetObjectItem(device_manager_info, "paras");
    if (paras == NULL) {
        OMIP_LOG_ERROR("cjson get object item failed\n");
        device_manager_rsp_api_channel6(mid, OMIP_PARAS_INVALID);
        return;
    }
    char *fmType = GET_JSON_ITEM(paras, "fmType", valuestring, "");
    if (strcmp(fmType, "module") == 0) {
    	OMIP_LOG_INFO( "module start\n");
        ret = omip_api_send(OMIP_VC_CHANNEL4, OMIP_CONTENT_FORMAT_JSON, HLINK_CMD_DEVICE_MANAGER,
                            (unsigned char *)data, len);
        if (ret != OMIP_OK) {
            OMIP_LOG_ERROR("omip send failed, dst_vc[%d] cmd[%d]\n",
                        OMIP_VC_CHANNEL4, HLINK_CMD_DEVICE_MANAGER);
        }
		device_manager_rsp_api_channel6(mid, ret);
    } else if (strcmp(fmType, "mcu") == 0) {
        OMIP_LOG_INFO("mcu upload debug info proc\n");
        ret = device_manager_debug_mcu_proc(device_manager_info, HLINK_UPLOAD_APP);
        OMIP_LOG_INFO("mcu upload log ret = %d", ret);
        device_manager_rsp_api_channel6(mid, ret);
    }
    return;
}

static int mcu_logfile_upload_notice(mcu_upload_logfile_direction direction)
{
    cJSON *notice = NULL;
    cJSON *paras = NULL;
    notice = cJSON_CreateObject();
    if (notice == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "creat notice object failed\n");
        return -1;
    }
    paras = cJSON_CreateObject();
    if (paras == NULL) {
        cJSON_Delete(notice);
        omip_printf(OMIP_ERROR_UPLOAD, "creat paras object failed\n");
        return -1;
    }
    cJSON_AddStringToObject(notice, "srv", "set");
    cJSON_AddStringToObject(notice, "cmd", "file");
    cJSON_AddStringToObject(paras, "operateCode", "upload");
    cJSON_AddStringToObject(paras, "fileName", "dev_logfile.txt");
    cJSON_AddStringToObject(paras, "fileType", "logfile");
    cJSON_AddNumberToObject(paras, "fileSize", 65536); // max logfile size 64k
    cJSON_AddItemToObject(notice, "paras", paras);
    char *result = cJSON_PrintUnformatted(notice);
    if (result == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "cjson print unformatted failed\n");
        cJSON_Delete(notice);
        return -1;
    }
    if (direction == MCU_UPLOAD_LOGFILE_APP) {
        device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_NOTICE, (uint8_t *)result, strlen(result));
    } else {
        device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_NOTICE, (uint8_t *)result, strlen(result));
    }
    omip_free(result);
    cJSON_Delete(notice);
    return 0;
}

void mcu_send_log_proc(uint32_t sector_addr, uint32_t logsize, omip_log_record_type type, 
												mcu_upload_logfile_direction direction)
{
    uint32_t read_len = 0;
    uint32_t left_logsize = logsize;
    uint32_t read_addr = sector_addr + sizeof(omip_log_sector_head);
    uint8_t file_mngr_buf[OMIP_FILE_MNGR_BUF + 1] = {0};

    omip_printf(OMIP_INFO_UPLOAD, "read_addr [0x%08x] logsize=%d\n", read_addr, logsize);
    while (left_logsize > 0) {
        if (left_logsize < OMIP_FILE_MNGR_BUF) { // read 1024 byte each time
            read_len = left_logsize;
        } else {
            read_len = OMIP_FILE_MNGR_BUF; // read 1024 byte each time
        }
        if (omip_read_by_type(LOGRECORD_ZONE, read_addr, file_mngr_buf, read_len, type) == 0) {
            left_logsize -= read_len;
            read_addr += read_len;
			if (direction == MCU_UPLOAD_LOGFILE_APP) {
				device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, file_mngr_buf, read_len);
			} else {
				device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, file_mngr_buf, read_len);
				osal_task_sleep(100); /* 100ms to send one block file to module */
			}
        } else {
            omip_printf(OMIP_ERROR_UPLOAD, "mcu read log from flash failed\n");
            break;
        }
    }
    return;
}

void mcu_get_cache_log(mcu_upload_logfile_direction direction)
{
	int send_len = 0;
	int read_len = 0;
    uint8_t file_mngr_buf[OMIP_FILE_MNGR_BUF + 1] = {0};
	cache_log_info * log_info = get_cache_log_info();
    if (log_info == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "mcu get log zone failed\n");
        return;
    }
	
	while (log_info->start_address + send_len < log_info->last_address)
	{
		if(log_info->start_address+send_len+OMIP_FILE_MNGR_BUF < log_info->last_address) {
			read_len = OMIP_FILE_MNGR_BUF;
		}
		else {
			read_len = log_info->last_address - log_info->start_address - send_len;
		}
		
		if(omip_read_cache_log(file_mngr_buf, log_info->start_address+send_len, read_len) != read_len) {
			return;
		}		
		if (direction == MCU_UPLOAD_LOGFILE_APP) {
			device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, file_mngr_buf, read_len);
		} else {
			device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, file_mngr_buf, read_len);
			osal_task_sleep(100); /* 100ms to send one block file to module */
		}
		send_len += read_len;
	}
	return;
}

void mcu_get_hlink_cache_log(mcu_upload_logfile_direction direction)
{
	int send_len = 0;
	int read_len = 0;
    uint8_t file_mngr_buf[OMIP_FILE_MNGR_BUF + 1] = {0};
	zone_info * log_zone = hlink_get_cache_log_zone_info();
    if (log_zone == NULL) {
        MCU_LOG(MCU_LOG_INFO_UPLOAD, "mcu get log zone failed\n");
        return;
    }
	MCU_LOG(MCU_LOG_INFO_UPLOAD, "update cache log start");
	while (log_zone->start_address + send_len < log_zone->last_address) {
		if(log_zone->start_address+send_len+OMIP_FILE_MNGR_BUF < log_zone->last_address) {
			read_len = OMIP_FILE_MNGR_BUF;
		}
		else {
			read_len = log_zone->last_address - log_zone->start_address - send_len;
		}
		
		if(hlink_read_cache_log(file_mngr_buf, log_zone->start_address+send_len, read_len) != read_len) {
			return;
		}
		if (direction == MCU_UPLOAD_LOGFILE_APP) {
			device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, file_mngr_buf, read_len);
		} else {
			device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, file_mngr_buf, read_len);
			osal_task_sleep(100); /* 100ms to send one block file to module */
		}
		send_len += read_len;
	}
	return;
}

void mcu_get_hlink_flash_log(mcu_upload_logfile_direction direction)
{
	int send_len = 0;
	int read_len = 0;
    uint8_t file_mngr_buf[OMIP_FILE_MNGR_BUF + 1] = {0};
	zone_info * log_zone = mcu_get_flash_zone(LOGRECORD_ZONE);
    if (log_zone == NULL) {
        MCU_LOG(MCU_LOG_INFO_UPLOAD, "mcu get log zone failed\n");
        return;
    }
	
	MCU_LOG(MCU_LOG_INFO_UPLOAD, "update flash log start");
	while (log_zone->start_address + send_len < log_zone->last_address) {
		if(log_zone->start_address+send_len+OMIP_FILE_MNGR_BUF < log_zone->last_address) {
			read_len = OMIP_FILE_MNGR_BUF;
		}
		else {
			read_len = log_zone->last_address - log_zone->start_address - send_len;
		}
		
		if(hlink_flash_log_read(file_mngr_buf, log_zone->start_address+send_len, read_len) != read_len) {
			return;
		}
		if (direction == MCU_UPLOAD_LOGFILE_APP) {
			device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, file_mngr_buf, read_len);
		} else {
			device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, file_mngr_buf, read_len);
			osal_task_sleep(100); /* 100ms to send one block file to module */
		}
		send_len += read_len;
	}
	return;
}


void mcu_get_log_from_flash(omip_log_record_type type, mcu_upload_logfile_direction direction)
{
    int ret = 0;
    zone_info *logrecord_zone = omip_get_zone_by_type(LOGRECORD_ZONE, type);
    if (logrecord_zone == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "mcu get log zone failed\n");
        return;
    }
    uint32_t sector_addr;
    uint32_t sector_num = (logrecord_zone->end_address - logrecord_zone->start_address + 1) / OMIP_FLASH_SECTOR_SIZE;
    omip_log_sector_head head = {0};
    for (uint8_t i = 0; i < sector_num; i++) {
        sector_addr = logrecord_zone->start_address + OMIP_FLASH_SECTOR_SIZE * i;
        ret = omip_log_get_head(sector_addr, &head, type);
        omip_printf(OMIP_DEBUG_UPLOAD, "mcu get log, addr[0x%08x] num[%d][%d] flag[0x%08x] logsize[%d] status[0x%08x]\n",
                    sector_addr, i, sector_num, head.flag, head.logsize, head.status);
        if (ret == 0) {
            if (head.flag != OMIP_VALID_LOG_FLAG) {
                continue;
            }
            mcu_send_log_proc(sector_addr, head.logsize, type, direction);
        }
    }
    omip_printf(OMIP_INFO_UPLOAD, "mcu get log finished\n");
    return;
}


static void mcu_logfile_upload_block(mcu_upload_logfile_direction direction)
{
    /* upload logfile from mcu cache */
	if (direction == MCU_UPLOAD_LOGFILE_APP) {
        device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_DIVIDE_LINE, strlen(OMIP_LOG_DIVIDE_LINE));
        device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_FROM_CACHE_LINE, strlen(OMIP_LOG_FROM_CACHE_LINE));
        device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_DIVIDE_LINE, strlen(OMIP_LOG_DIVIDE_LINE));
    } else {
        device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_DIVIDE_LINE, strlen(OMIP_LOG_DIVIDE_LINE));
        device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_FROM_CACHE_LINE, strlen(OMIP_LOG_FROM_CACHE_LINE));
        device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_DIVIDE_LINE, strlen(OMIP_LOG_DIVIDE_LINE));
    }
    mcu_get_hlink_cache_log(direction);

    /* upload logfile from mcu flash */
    if (direction == MCU_UPLOAD_LOGFILE_APP) {
        device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_DIVIDE_LINE, strlen(OMIP_LOG_DIVIDE_LINE));
        device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_FROM_FLASH_LINE, strlen(OMIP_LOG_FROM_CACHE_LINE));
        device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_DIVIDE_LINE, strlen(OMIP_LOG_DIVIDE_LINE));
    } else {
        device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_DIVIDE_LINE, strlen(OMIP_LOG_DIVIDE_LINE));
        device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_FROM_FLASH_LINE, strlen(OMIP_LOG_FROM_CACHE_LINE));
        device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK, (uint8_t *)OMIP_LOG_DIVIDE_LINE, strlen(OMIP_LOG_DIVIDE_LINE));
    }
    mcu_get_hlink_flash_log(direction);

}

static void mcu_logfile_upload_block_end(mcu_upload_logfile_direction direction)
{
    cJSON *block_end = NULL;
    cJSON *paras = NULL;
    block_end = cJSON_CreateObject();
    if (block_end == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "cjson create block end object failed\n");
        return;
    }
    paras = cJSON_CreateObject();
    if (paras == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "cjson create paras object failed\n");
        cJSON_Delete(block_end);
        return;
    }
    cJSON_AddStringToObject(block_end, "srv", "set");
    cJSON_AddStringToObject(block_end, "cmd", "file");
    cJSON_AddStringToObject(paras, "fileName", "dev_logfile.txt");
    cJSON_AddItemToObject(block_end, "paras", paras);
    char *result = cJSON_PrintUnformatted(block_end);
    if (result == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "cjson print unformate failed\n");
        cJSON_Delete(block_end);
        return;
    }
    if (direction == MCU_UPLOAD_LOGFILE_APP) {
        device_manager_rsp_channel6(HLINK_CMD_FILE_MNGR_BLOCK_END, (uint8_t *)result, strlen(result));
    } else {
        device_manager_rsp_channel4(HLINK_CMD_FILE_MNGR_BLOCK_END, (uint8_t *)result, strlen(result));
    }
    omip_free(result);
    cJSON_Delete(block_end);
    return;
}


void device_manager_logfile_mcu_proc(void *arg)
{
	 mcu_upload_logfile_direction direction = *(mcu_upload_logfile_direction *)arg;
    /* 1.send notice */
    int ret = mcu_logfile_upload_notice(direction);
    if (ret != 0) {
        omip_printf(OMIP_ERROR_UPLOAD, "mcu logfile upload notice failed");
        free(arg);
        g_mcu_log_upload_task_id = NULL;
		LOS_TaskDelete(LOS_CurTaskIDGet());
        return;
    }
    /* 2.send block */
    mcu_logfile_upload_block(direction);
    /* 3.send end */
    mcu_logfile_upload_block_end(direction);
    /* 4.exit task */
    omip_free(arg);
    g_mcu_log_upload_task_id = NULL;
	LOS_TaskDelete(LOS_CurTaskIDGet());
    return;
}


void device_manager_logfile_mcu_task_create(mcu_upload_logfile_direction upload_direction)
{
    omip_printf(OMIP_INFO_UPLOAD, "start creat mcu logfile upload task!\r\n");
	    /* if mcu is uploading logfile to gateway, return busy */
    if (g_mcu_log_upload_task_id != NULL) {
        omip_printf(OMIP_ERROR, "mcu logfile upload is busy, please try again later!\n");
        return;
    }
    mcu_upload_logfile_direction *direction = malloc(sizeof(mcu_upload_logfile_direction));
    if (direction == NULL) {
        omip_printf(OMIP_ERROR, "mcu malloc upload file direction failed\n");
        return;
    }
    *direction = upload_direction;
    g_mcu_log_upload_task_id = osal_task_create("mcu_logfile_upload",(int (*)(void *))device_manager_logfile_mcu_proc,
                                 (void *)direction, 1024*8, NULL, 23);
    if (g_mcu_log_upload_task_id == NULL) {
        omip_printf(OMIP_ERROR, "osal_task_create mcu_logfile_upload failed\n");
        omip_free(direction);
    }
	return;
}

static void device_manager_logfile_proc(cJSON *device_manager_info, uint8_t* data, int len)
{
    int mid = GET_JSON_ITEM(device_manager_info, "mid", valueint, -1);
    cJSON *paras = cJSON_GetObjectItem(device_manager_info, "paras");
    if (paras == NULL) {
        omip_printf(OMIP_ERROR, "get object item paras failed\n");
        device_manager_rsp_api_channel6(mid, OMIP_PARAS_INVALID);
        return;
    }
    char *fmType = GET_JSON_ITEM(paras, "fmType", valuestring, "");
    if (strcmp(fmType, "module") == 0) {
        omip_printf(OMIP_INFO, "send upload logfile json to module\n");
        int ret = omip_api_send(OMIP_VC_CHANNEL4, OMIP_CONTENT_FORMAT_BINARY, HLINK_CMD_DEVICE_MANAGER,
                                (unsigned char *)data, len);
        if (ret != OMIP_OK) {
            omip_printf(OMIP_ERROR, "omip send failed, dst_vc[%d] cmd[%d]", OMIP_VC_CHANNEL4,
                        HLINK_CMD_DEVICE_MANAGER);
            device_manager_rsp_api_channel6(mid, ret);
        }
    } else if (strcmp(fmType, "mcu") == 0) {
        omip_printf(OMIP_INFO, "mcu upload logfile proc\r\n");
        device_manager_logfile_mcu_task_create(MCU_UPLOAD_LOGFILE_APP);
    } else {
        omip_printf(OMIP_ERROR, "mcu get fmType failed\n");
        device_manager_rsp_api_channel6(mid, OMIP_PARAS_INVALID);
    }
}

static void device_manager_sendto_module_process(cJSON *device_manager_info, uint8_t* data, int len)
{
	int mid = GET_JSON_ITEM(device_manager_info, "mid", valueint, -1);
	int ret = omip_api_send(OMIP_VC_CHANNEL4, OMIP_CONTENT_FORMAT_JSON, HLINK_CMD_DEVICE_MANAGER,
                        (unsigned char *)data, len);
	if (ret != OMIP_OK) {
        omip_printf(OMIP_ERROR, "omip send failed, dst_vc[%d] cmd[%d]\n",
                    OMIP_VC_CHANNEL4, HLINK_CMD_DEVICE_MANAGER);
        device_manager_rsp_api_channel6(mid, ret);
    }
}

static void device_manager_query_loglevel_mcu_proc(cJSON *device_manager_info, uint8_t* data, int len)
{
	int mid = GET_JSON_ITEM(device_manager_info, "mid", valueint, -1);
    omip_log_level level = hlink_log_level_get();
    char* loglevel = hlink_get_level_string(level);
    cJSON *rsp = NULL;
    cJSON *loginfoList = NULL;

    rsp = cJSON_CreateObject();
    if (rsp == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "cjson create object failed\n");
        return;
    }
    loginfoList = cJSON_CreateObject();
    if (loginfoList == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "cjson create loginfoList object failed\n");
        cJSON_Delete(rsp);
        return;
    }
    cJSON_AddNumberToObject(rsp, "mid", mid);
    cJSON_AddNumberToObject(rsp, "errcode", 0);
    cJSON_AddStringToObject(rsp, "status", "reserve"); /* 保留 */
    cJSON_AddStringToObject(loginfoList, "fmType", "mcu");
    cJSON_AddStringToObject(loginfoList, "level", loglevel);
    cJSON_AddItemToObject(rsp, "loginfoList", loginfoList);
    char *result = cJSON_PrintUnformatted(rsp);

    if (result == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "cjson print unformate failed\n");
        cJSON_Delete(rsp);
        return;
    }
    omip_printf(OMIP_INFO_UPLOAD, "\n====query loglevel rsp: %s\n", result);
    device_manager_rsp_channel6(HLINK_CMD_DEVICE_MANAGER_RSP, (uint8_t *)result, strlen(result));
    omip_free(result);
    cJSON_Delete(rsp);
    return;
}

static void device_manager_query_loglevel_process(cJSON *device_manager_info, uint8_t* data, int len)
{
    int mid = GET_JSON_ITEM(device_manager_info, "mid", valueint, -1);
    cJSON *paras = cJSON_GetObjectItem(device_manager_info, "paras");
    if (paras == NULL) {
        omip_printf(OMIP_ERROR_UPLOAD, "cjson get object item failed\n");
        device_manager_rsp_api_channel6(mid, OMIP_PARAS_INVALID);
        return;
    }

    char *fmType = GET_JSON_ITEM(paras, "fmType", valuestring, "");
    if (strcmp(fmType, "mcu") == 0) {
        omip_printf(OMIP_INFO_UPLOAD, "mcu query loglevel proc\n");
        device_manager_query_loglevel_mcu_proc(device_manager_info, data, len);
    } else if (strcmp(fmType, "module") == 0) {
        omip_printf(OMIP_INFO_UPLOAD, "send to module, set loglevel proc\n");
        /* 设置模组日志级别, 透传给模组处理 */
        device_manager_sendto_module_process(device_manager_info, data, len);
    }

    return;
}

static void device_manager_set_loglevel_process(cJSON *device_manager_info, uint8_t* data, int len)
{
    int ret = -1;
    int mid = GET_JSON_ITEM(device_manager_info, "mid", valueint, -1);
    cJSON *paras = cJSON_GetObjectItem(device_manager_info, "paras");
    if (paras == NULL) {
        omip_printf(OMIP_ERROR, "cjson get object item failed\n");
        device_manager_rsp_api_channel6(mid, OMIP_PARAS_INVALID);
        return;
    }

    char *fmType = GET_JSON_ITEM(paras, "fmType", valuestring, "");
    if (strcmp(fmType, "mcu") == 0) {
        omip_printf(OMIP_INFO, "mcu set loglevel proc\n");
        /* 设置mcu日志级别 */
        cJSON *paras = cJSON_GetObjectItem(device_manager_info, "paras");
        char *level = GET_JSON_ITEM(paras, "level", valuestring, "");
        ret = device_manager_set_loglevel_mcu_proc(level);
    } else if (strcmp(fmType, "module") == 0) {
        omip_printf(OMIP_INFO, "send to module, set loglevel proc\n");
        /* 设置模组日志级别, 透传给模组处理 */
        device_manager_sendto_module_process(device_manager_info, data, len);
        return;
    } else {
        ret = OMIP_PARAS_INVALID;
    }

    device_manager_rsp_api_channel6(mid, ret);
    return;
}


void send_dev_update_btv_json(char *ble_version)
{
    cJSON* root = NULL;
    cJSON* item_devinfo = NULL;

    root = cJSON_CreateObject();
    item_devinfo = cJSON_CreateObject();
    if ((root == NULL) || (item_devinfo == NULL))
    {
        OMIP_LOG_ERROR("cJSON_CreateObject failed\n");
        goto failed_exit;
    }

    cJSON_AddStringToObject(item_devinfo, "sn", g_mcu_sn);
    cJSON_AddStringToObject(item_devinfo, "btv", ble_version);

    cJSON_AddItemToObject(root, "devInfo", item_devinfo);

    char* update_char = cJSON_PrintUnformatted(root);
	OMIP_LOG_INFO("hlink cmd:%d, json:%s", HLINK_CMD_DEV_INFO_UPDATE, update_char);
    if (omip_api_send(OMIP_VC_DEFAULT0, OMIP_CONTENT_FORMAT_JSON, HLINK_CMD_DEV_INFO_UPDATE, (uint8_t *)update_char, strlen(update_char)+1) != OMIP_OK)
    {
        OMIP_LOG_ERROR("====omip_api_send HLINK_CMD_DEV_INFO_UPDATE failed!\r\n");
    }
    omip_free(update_char);
    cJSON_Delete(root);
    return;

failed_exit:
    if (root)
    {
        cJSON_Delete(root);
    }
    if (item_devinfo)
    {
        cJSON_Delete(item_devinfo);
    }
}


void mcu_recv_ble_version_process(uint8_t *data, unsigned int len)
{
    char ble_version[32] = {0};
    ble_dev_mng_req ble_dev_mng = {0};
    if(EOK != memcpy_s(&ble_dev_mng, sizeof(ble_dev_mng_req), data, len))
    {
        OMIP_LOG_ERROR("memcpy_s ble_dev_mng failed!\r\n");
    }

    if(ble_dev_mng.operate == BLE_VERSION_REPORT)
    {
        if(EOK != memcpy_s(ble_version, 32, ble_dev_mng.payload, strlen(ble_dev_mng.payload)+1))
        {
             OMIP_LOG_ERROR("memcpy_s ble_version failed!\r\n");
        }
        OMIP_LOG_INFO("1the ble_version is %s; the g_ble_version is %s\n", ble_version,g_ble_version);
        if(strcmp(g_ble_version,ble_version) != 0 && strlen(g_ble_version) > 0) // && g_dev_info->accept_ct == HLINK_SERVICE_CT_JSON) //g_dev_info->accept_ct == HLINK_SERVICE_CT_JSON代表已经进行过设备注册
        {
            send_dev_update_btv_json(ble_version);
        }

        if(EOK != memcpy_s(g_ble_version, 32, ble_version, strlen(ble_version)+1))
        {
            OMIP_LOG_ERROR("memcpy_s g_ble_version failed!\r\n");
        }
        OMIP_LOG_INFO("2the ble_version is %s; the g_ble_version is %s\n", ble_version,g_ble_version);
    }
}

void omip_cmd_process_demo(uint8_t vc,uint8_t ct,uint16_t hlnk_cmd,uint8_t* data,int len) //以太网HLINK消息
{
	if(ct == OMIP_CONTENT_FORMAT_JSON) {
		OMIP_LOG_INFO("hlnk_cmd:0x%04X", hlnk_cmd);
		OMIP_LOG_INFO("json data[%d]:%s\r\n", len, len>360? "<too long>": (char *)data);
	}
	else if(HLINK_CMD_FILE_MNGR_BLOCK != hlnk_cmd
		&& HLINK_CMD_CONNECT_BEATHEART !=  hlnk_cmd){
		OMIP_LOG_INFO("hlnk_cmd:0x%04X,bin data[%d]\r\n",hlnk_cmd,len);
	}
	
    cJSON *pJsMsg =(ct==OMIP_CONTENT_FORMAT_JSON?cJSON_Parse((char*)data):NULL);

	struct omip_context_tag *context = omip_get_context();
	if(context->sock[vc].support_auth == 1)
    {
        if((hlnk_cmd!=HLINK_CMD_CONNECT_REQ &&hlnk_cmd!=HLINK_CMD_CONNECT_AUTH_RSP) &&mcu_auth_app_msg(vc,data,len)!=0)
			{if(pJsMsg) cJSON_Delete(pJsMsg); return;}
    }
	
    switch (hlnk_cmd) {
    case HLINK_CMD_DEVICE_MANAGER:
		if(OMIP_CONTENT_FORMAT_BINARY == ct) {
			device_manger_binary(ct, data, len);
		}
		else if(OMIP_CONTENT_FORMAT_JSON == ct) {
			device_manger_json(ct, data, len);
		}
			
        break;
	case HLINK_CMD_DEVICE_MANAGER_RSP: //日志上报、日志文件上报、查询证书等的回复
		mcu_general_send_ble(hlnk_cmd,ct,data,len); //原封不动转发给蓝牙
		break;
	case HLINK_CMD_DATA_REPORT_APP: //日志上报APP
		mcu_general_send_ble(hlnk_cmd,ct,data,len); //原封不动转发给蓝牙
		break;
    case HLINK_CMD_DEL_DEV_RSP:
        mcu_del_virtualDev();
        break;
    case HLINK_CMD_DEV_REG_RSP:
        get_dev_reg_rsp(ct, data, len);
		synchronize_time_request();
#if SUPPORT_DEV_UPDATE
        send_dev_update_req_json();
#endif
#if SUPPORT_EXT_DEV
        osal_task_sleep(3000);
        send_add_extdev_req();
#endif
		

        break;
    case HLINK_CMD_DEV_INFO_UPDATE_RSP:
        get_dev_update_rsp(ct, data, len);
        break;
    case HLINK_CMD_EXTDEV_ADD_RSP:
        recv_add_extdev_rsp(ct, data, len);
        osal_task_sleep(3000);
        send_update_extdev_req();
        break;
    case HLINK_CMD_EXTDEV_UPDATE_RSP:
        recv_update_extdev_rsp(ct, data, len);
        break;
    case HLINK_CMD_FILE_MNGR_NOTICE: //文件传输通知
		g_update_flag = 1;
        get_file_mngr_notice(ct, data, len); //处理下发文件通知
        break;
    case HLINK_CMD_FILE_MNGR_BLOCK: //文件数据到达
    	get_file_mngr_block(ct, data, len); //文件数据处理
        break;
    case HLINK_CMD_FILE_MNGR_BLOCK_END: //文件数据传输完毕
		g_update_flag = 0;
    	get_file_mngr_block_end(ct, data, len); //文件数据传输完毕
        break;
	case HLINK_CMD_FILE_MNGR_RESULT: //可能是证书下发到模组后的回复
		if (strcmp((const char*)g_notice_msg.file_type, "package") == 0)
		{
			if (ct == OMIP_CONTENT_FORMAT_JSON)
			{
				int upgrade_result = get_file_rsp_errcode((const char*)data);
				OMIP_LOG_INFO( "hlink module upgrade result = %d\n", upgrade_result);
                set_hlink_upgrade_result(upgrade_result);
            }
		}
		mcu_general_send_ble(hlnk_cmd,ct,data,len); //原封不动转发给蓝牙
		break;
    case HLINK_CMD_DATA_REPORT_RSP:
		
        break;
    case HLINK_CMD_MODULE_ONLINE:
        get_hlink_info(ct, data, len);
		send_device_reg_req_json();
        //send_device_reg_req();
        break;
    case HLINK_CMD_SRV_CMD:
	case HLINK_CMD_SRV_TRACE_CMD:
        process_srv_cmd(ct, data, len, hlnk_cmd); //receive srvcmd from hlink
        //synchronize_time_request();   //synchronize time from hlink
        break;
    case HLINK_CMD_SET_MODULE_CONF:
        mcu_recv_set_module_config(data,len);
        break;
    case HLINK_CMD_SET_MODULE_CONF_RSP: //设置WIFI模组后模组返回信息
    	omip_printf(OMIP_INFO,"[%s:%d]config result: %s\r\n",__FUNCTION__,__LINE__,(char *)data);
		mcu_general_send_ble(hlnk_cmd,ct,data,len); //原封不动转发给蓝牙
        break;
    case HLINK_CMD_GET_MODULE_CONF:
        mcu_recv_get_module_config(data,len);
        break;
    case HLINK_CMD_GET_MODULE_CONF_RSP: //获取WIFI模组配置后模组返回信息
    	omip_printf(OMIP_INFO,"[%s:%d]get config result: %s\r\n",__FUNCTION__,__LINE__,(char *)data);
		mcu_general_send_ble(hlnk_cmd,ct,data,len); //原封不动转发给蓝牙
        break;
    case HLINK_CMD_SYN_TIME_RSP:
        if((NULL!=data) &&(len==sizeof(unsigned long long))) synchronize_time_response(*((unsigned long long *)data));
        break;
	
	case HLINK_CMD_CONNECT_BEATHEART:
		get_cmd_connect_beatheart(ct, data, len);
		break;
    case HLINK_CMD_GET_MCU_INFO:
    case HLINK_CMD_ADD_DEV:
    case HLINK_CMD_GET_DEV:
        break;
    default:
        OMIP_LOG_INFO("******unknown cmd:0x%x ct:%d******\r\n", hlnk_cmd,ct);
        break;
    }
	if(pJsMsg) cJSON_Delete(pJsMsg);
}

void omip_cmd_process_ble(uint8_t vc,uint8_t ct,uint16_t ble_cmd,uint8_t* data,int len) //蓝牙HLINK消息
{
	if(ct==OMIP_CONTENT_FORMAT_JSON) {
		OMIP_LOG_INFO("ble_cmd:0x%04X", ble_cmd);
		OMIP_LOG_INFO("json data[%d]:%s\r\n", len, len>360? "<too long>": (char *)data);
	}
	else if(HLINK_CMD_FILE_MNGR_BLOCK != ble_cmd
		&& HLINK_CMD_BLE_FILE_MNGR_ACK != ble_cmd){
		OMIP_LOG_INFO("ble_cmd:0x%04X,bin data[%d]",ble_cmd,len);
	}
	
    cJSON *pJsMsg = cJSON_Parse((char *)data);
	int   mid =(pJsMsg?GET_JSON_ITEM(pJsMsg,"mid",valueint,-1):-1);
	char *srv =(pJsMsg?GET_JSON_ITEM(pJsMsg,"srv",valuestring,""):"");
	char *cmd =(pJsMsg?GET_JSON_ITEM(pJsMsg,"cmd",valuestring,""):"");
	if(cmd[0]=='\0') {
		cmd = (pJsMsg?GET_JSON_ITEM(pJsMsg,"cmd ",valuestring,""):""); //手机APP有BUG，有时会多一个空格
	}
	switch (ble_cmd) {
    case HLINK_CMD_BLE_NOTIFY:
        mcu_recv_ble_notify(vc,data,len);
        break;
    case HLINK_CMD_CONNECT_REQ:
        mcu_recv_security_connect_req(vc,data,len);
        break;
    case HLINK_CMD_CONNECT_AUTH_RSP:
        mcu_recv_security_connect_auth_rsp(vc,data,len);
        break;
    case HLINK_CMD_FILE_MNGR_NOTICE: //update notice
    	g_update_flag = 1;
    	get_ble_file_mngr_notice(ct,data,len); //处理蓝牙下发文件通知
        break;
    case HLINK_CMD_FILE_MNGR_BLOCK: //update file data
        get_ble_file_mngr_block(ct,data,len); //蓝牙文件数据处理
        break;
    case HLINK_CMD_FILE_MNGR_BLOCK_END: //update file send data end
		g_update_flag = 0;
		get_ble_file_mngr_block_end(ct,data,len); //蓝牙文件数据传输完毕
        break;
	case HLINK_CMD_BLE_FILE_MNGR_ACK: //准备升级蓝牙固件时蓝牙的回复
		if(len==5)
		{
			g_file_trans.ble_ota_res = data[0]; //蓝牙OTA回复标志置位
			g_file_trans.ble_ota_tmout =*(unsigned int *)(data+1);
			osal_semp_post(Mutex_ble_handle);
		}
		break;
	case HLINK_CMD_BLE_FILE_MNGR_RESULT: //升级蓝牙固件完成时蓝牙的回复
	    mcu_recv_ble_file_mngr_result_process(vc, ct, data, len);
		break;
	case HLINK_CMD_FILE_MNGR_RESULT: //可能是日志文件上传APP的回复
		if (strcmp((const char*)g_notice_msg.file_type, "package") == 0) {
			if (ct == OMIP_CONTENT_FORMAT_JSON) {
				int upgrade_result = get_file_rsp_errcode((const char*)data);
				OMIP_LOG_INFO( "hlink module upgrade result = %d\n", upgrade_result);
                set_hlink_upgrade_result(upgrade_result);
            }
		}
		mcu_general_send_ble(ble_cmd,ct,data,len); //原封不动转发给蓝牙
		//omip_api_send(OMIP_VC_DEFAULT0,ct,ble_cmd,data,len); //直接转发到模组(WIFI或PLC)
		break;
	case HLINK_CMD_SET_MODULE_CONF: //设置WIFI模块配置
		if(mcu_check_auth(vc)<=0) {mcu_send_json_ble(HLINK_CMD_SET_MODULE_CONF_RSP,make_ble_respond_json(mid,0,99),1); break;} //还没有通过认证
		if(strcmp("net",cmd)==0) ble_set_wifi(data,len); //直接设置WIFI参数，现在不做回复，等WIFI回复了再回复蓝牙
		break;
	case HLINK_CMD_GET_MODULE_CONF: //查询WIFI模块配置
		if(mcu_check_auth(vc)<=0) {mcu_send_json_ble(HLINK_CMD_GET_MODULE_CONF_RSP,make_ble_respond_json(mid,0,99),1); break;} //还没有通过认证
		if(strcmp("net",cmd)==0) ble_get_wifi(data,len); //直接设置WIFI参数，现在不做回复，等WIFI回复了再回复蓝牙
		break;
	case HLINK_CMD_GET_MCU_INFO: //控制器信息
		if(mcu_check_auth(vc)<=0) {mcu_send_json_ble(HLINK_CMD_GET_MCU_INFO_RSP,make_ble_respond_json(mid,0,99),1); break;} //还没有通过认证
		if(strcmp("devinfo",srv)==0)
		{
			if(strcmp("query",cmd)==0) //蓝牙查询设备信息
			{
				cJSON *pJsRet =make_ble_respond_json(mid,0,0);
				make_dev_info(pJsRet); //打包设备信息到JSON
				mcu_send_json_ble(HLINK_CMD_GET_MCU_INFO_RSP,pJsRet,1);
			}
			else if(strcmp("set",cmd)==0) //蓝牙查询设备信息
			{
				cJSON *json_paras =cJSON_GetObjectItem(pJsMsg,"paras");
				if(json_paras) change_dev_info(json_paras);
				mcu_send_json_ble(HLINK_CMD_GET_MCU_INFO_RSP,make_ble_respond_json(mid,0,0),1);
			}
		}
	case HLINK_CMD_ADD_DEV: //添加设备
		if(mcu_check_auth(vc)<=0) {mcu_send_json_ble(HLINK_CMD_ADD_DEV_RSP,make_ble_respond_json(mid,0,99),1); break;} //还没有通过认证
		if(strcmp("dev",cmd)==0 && strcmp("set",srv)==0)
		{
			cJSON *json_paras =cJSON_GetObjectItem(pJsMsg,"paras");
			char *dev_data = cJSON_PrintUnformatted(json_paras);
			g_flash_dev =file_addr_init("dev",FILE_BL_DEV_ADDR,FILE_BL_DEV_SIZE);
			g_flash_dev->buff = (char *)malloc(sizeof(uint8_t)*(strlen(dev_data)+1));
			strcpy(g_flash_dev->buff,dev_data);
			omip_free(dev_data);
			omip_printf(OMIP_INFO,"[%s:%d]devinfo set data(%d):%s\r\n",__FUNCTION__,__LINE__,g_flash_dev->size,(char *)(g_flash_dev->buff));
			save_data_to_file(g_flash_dev);
			free_w25flash_t(&g_flash_dev);
			mcu_send_json_ble(HLINK_CMD_ADD_DEV_RSP,make_ble_respond_json(mid,0,0),1);
			send_dev_update_req_json(); //向以太网HLINK更新设备注册信息
		}
		break;
	case HLINK_CMD_DEL_DEV: //删除设备
		if(mcu_check_auth(vc)<=0) {mcu_send_json_ble(HLINK_CMD_DEL_DEV_RSP,make_ble_respond_json(mid,0,99),1); break;} //还没有通过认证
		if(strcmp("dev",cmd)==0 && strcmp("delete",srv)==0)
		{
			cJSON *pJsRet =make_ble_respond_json(mid,0,0);
	        cJSON_DeleteItemFromObject(pJsRet,"status");
            cJSON_AddStringToObject(pJsRet,"status","reserve");
			mcu_send_json_ble(HLINK_CMD_DEL_DEV_RSP,pJsRet,1);
			mcu_del_virtualDev(); //删除虚拟设备
		}
		break;
	case HLINK_CMD_DEVICE_MANAGER: //设备管理
		if(mcu_check_auth(vc)<=0) { //还没有通过认证
			mcu_send_json_ble(HLINK_CMD_DEVICE_MANAGER_RSP,make_ble_respond_json(mid,0,99),1); 
			break;
		} 
		if(strcmp("query",cmd)==0 && strcmp("version",srv)==0)
		{
			cJSON *pJsRet =make_ble_respond_json(mid,0,0);
			cJSON *pJsParas =cJSON_CreateObject();
			cJSON_AddStringToObject(pJsParas,"fwv", g_mcu_version);
			cJSON_AddStringToObject(pJsParas,"hlv", (char *)g_hlink_info.hiv);
			cJSON_AddStringToObject(pJsParas,"btv", g_ble_version);
			cJSON_AddItemToObject(pJsRet,"paras",pJsParas);
			mcu_send_json_ble(HLINK_CMD_DEVICE_MANAGER_RSP,pJsRet,1); //回复蓝牙
		}
		else if(strcmp("reboot",cmd)==0 && strcmp("devm",srv)==0) //复位设备自身
		{
			mcu_send_json_ble(HLINK_CMD_DEVICE_MANAGER_RSP,make_ble_respond_json(mid,0,0),1);
			system_reset_delay();
		}
		else if(strcmp("debug_info",srv) == 0) //日志上报开启/关闭请求,直接转发到模组(WIFI或PLC)
		{
			device_manager_debug_info_proc(pJsMsg, data, len);
		}
		else if(strcmp("logfile",srv)==0) //日志文件上报请求,直接转发到模组(WIFI或PLC)
		{
			OMIP_LOG_INFO( "upload logfile start!!!!");
			device_manager_logfile_proc(pJsMsg, data, len);
		}
		else if(strcmp("query",cmd)==0 &&strcmp("cert",srv)==0) //APP查询模组(WIFI或PLC)证书,直接转发到模组(WIFI或PLC)
		{
			if(omip_api_send(OMIP_VC_DEFAULT0,ct,ble_cmd,data,len)==OMIP_OK) ble_api_send(mid,CMD_RESPOND,NULL,4);
		}
		else if(strcmp("query",srv)==0 &&strcmp("log_level",cmd)==0) {
			device_manager_query_loglevel_process(pJsMsg, data, len);
		}
		else if(strcmp(srv, "set") == 0 && strcmp(cmd, "log_level") == 0) {
			device_manager_set_loglevel_process(pJsMsg, data, len);
		}
		else {
			device_manager_rsp_api_channel6(mid, OMIP_PARAS_INVALID);
		}
		break;
	case HLINK_CMD_DEVICE_MANAGER_RSP: //设备管理回复
		//模组响应，透传到蓝牙
		mcu_general_send_ble(ble_cmd, ct, data, len);
		break;
	case HLINK_CMD_DATA_REPORT_APP_RSP: //日志上报APP的回复
		device_manager_rsp_channel6(HLINK_CMD_DEVICE_MANAGER_RSP, data, len);
		//omip_api_send(OMIP_VC_DEFAULT0,ct,ble_cmd,data,len); //直接转发到模组(WIFI或PLC)
		break;
	case HLINK_CMD_SRV_CMD: //网关下发到MCU的命令字，由模组透传到MCU侧
		if(ct ==OMIP_CONTENT_FORMAT_ASN1_DER) //读取点位
		{
			process_point_rw(OMIP_VC_CHANNEL6,(char *)data ,len, HLINK_CMD_SRV_CMD);
		}
		break;
		
	case HLINK_CMD_DATA_REPORT_APP: //日志上报APP
		mcu_general_send_ble(ble_cmd,ct,data,len); //原封不动转发给蓝牙
		break;
	
    case HLINK_CMD_BLE_DEV_MNG_REQ:
        mcu_recv_ble_version_process(data, len);
        break;
	
    default:
		omip_printf(OMIP_ERROR,"[%s:%d]unknow ble cmd:0x%04X.\r\n",__FUNCTION__,__LINE__,ble_cmd);
  		break;
	}
	if(pJsMsg) cJSON_Delete(pJsMsg);
}

void mcu_device_log_upload_app_rsp(uint8_t* data, int len)
{
    omip_transaction send_ts = {0};
    send_ts.vc = OMIP_VC_CHANNEL6;
    send_ts.relay_flag = 0;
    send_ts.relay_vc = 0;
    send_ts.ctf = OMIP_CONTENT_FORMAT_JSON;
    send_ts.cmd = HLINK_CMD_DATA_REPORT_APP;

    send_ts.data = (unsigned char *)data;
    send_ts.len = len;
    send_ts.timeout = OMIP_SEND_DEFAULT;  //default 2s
    send_ts.ext_io_flag = OMIP_ENCODE_EXT; //when send to BLE, must chose this
    if(omip_send(&send_ts) != OMIP_OK) {
        omip_printf(OMIP_ERROR, "omip send failed, cmd[%04x]\n", HLINK_CMD_DATA_REPORT_APP);
    }
    return;
}

void omip_device_log_upload_app(const char *logBuffer)
{
    cJSON *upload_log = NULL;
    cJSON *paras = NULL;

    upload_log = cJSON_CreateObject();
    if (upload_log == NULL) {
        omip_printf(OMIP_ERROR, "creat json object failed");
        return;
    }
    paras = cJSON_CreateObject();
    if (paras == NULL) {
        cJSON_Delete(upload_log);
        omip_printf(OMIP_ERROR, "creat json object failed");
        return;
    }
    cJSON_AddStringToObject(upload_log, "srv", "debug_info");
    cJSON_AddStringToObject(upload_log, "cmd", "upload");
    cJSON_AddNumberToObject(upload_log, "mid", 1);
    cJSON_AddStringToObject(paras, "data", logBuffer);
    cJSON_AddItemToObject(upload_log, "paras", paras);
    char *result = cJSON_PrintUnformatted(upload_log);
    if (result == NULL) {
        cJSON_Delete(upload_log);
        return;
    }
    mcu_device_log_upload_app_rsp((uint8_t *)result, strlen(result));
    omip_free(result);
    cJSON_Delete(upload_log);
    return;
}


void mcu_demo_report_entry(void *args)         //this task is used only for test report data
{
    unsigned int report_times =0;
    uint8_t data_report[] ={JSON_REPORT_DATA};
    uint16_t len =(uint16_t)strlen((char*)data_report);
    while(1)
    {
        osal_task_sleep(10 *3000);
        report_times++;
        omip_printf(OMIP_DEBUG,"report_times %d\r\n", report_times);
        if(omip_api_send(OMIP_VC_DEFAULT0,OMIP_CONTENT_FORMAT_JSON,HLINK_CMD_DATA_REPORT,data_report,len) !=OMIP_OK)
            omip_printf(OMIP_ERROR, "[%s:%d]omip_api_send failed!\r\n",__FUNCTION__,__LINE__);
        osal_task_sleep(10 *8000);
    }
}

void mcu_start_user_report_task()
{
    void *pid =osal_task_create("start_user_report",(int (*)(void *))mcu_demo_report_entry,NULL,1024*2,NULL,23);
    if(pid ==NULL) omip_printf(OMIP_ERROR,"[%s:%d]osal_task_create failed!\r\n",__FUNCTION__,__LINE__);
}

static void check_sn() //检测SN号，如果没有就自动生成
{
	g_flash_sn = file_addr_init("sn",FILE_BL_SN_ADDR,FILE_BL_SN_SIZE);
	g_flash_sn->buff = (char *)malloc(sizeof(uint8_t)*g_flash_sn->size);
	read_data_from_file(g_flash_sn);
	char *pSn =(char *)g_flash_sn->buff;
	OMIP_LOG_INFO("M_SN:%s\r\n",pSn);
	
	int iSnError =0;
	if(strlen(pSn) < 1)
	{
		iSnError = 1;
	}
	for(int i=0; i<strlen(pSn) && i<64; i++)
	{
		if(((pSn[i] >= '0') && (pSn[i] <= '9')) || ((pSn[i] >= 'A') && (pSn[i] <= 'z'))) continue;		
		OMIP_LOG_ERROR_FLASH("M_SN[%d]:%c(0x%x) invalid",  i, pSn[i], pSn[i]);
		iSnError =1; break;
	}
	
	//读取备份的
	w25flash_t *bk_flash_sn = file_addr_init("bksn",FILE_BL_BKSN_ADDR,FILE_BL_BKSN_SIZE);
	bk_flash_sn->buff = (char *)malloc(sizeof(uint8_t)*bk_flash_sn->size);
	read_data_from_file(bk_flash_sn);
	OMIP_LOG_INFO("B_SN(0x%08lx):%s\r\n", bk_flash_sn->flash_start_addr, bk_flash_sn->buff);

	if(0 == iSnError) {
		//同步到备份区
		if(0 != memcmp(bk_flash_sn->buff, g_flash_sn->buff, bk_flash_sn->size)) {
			memcpy(bk_flash_sn->buff, g_flash_sn->buff, bk_flash_sn->size);
			save_data_to_file(bk_flash_sn);
		}
		memcpy(g_mcu_sn, bk_flash_sn->buff, bk_flash_sn->size);
		free_w25flash_t(&bk_flash_sn);
		free_w25flash_t(&g_flash_sn); 
		return;
	}

	//校查备份区SN
	pSn =(char *)bk_flash_sn->buff;
	iSnError =0;
	if(strlen(pSn) < 1)
	{
		iSnError = 1;
	}
	for(int i=0; i<strlen(pSn) && i<64; i++)
	{
		if((pSn[i]>='0' && pSn[i] <= '9') ||(pSn[i]>='A' && pSn[i] <= 'z')) continue;
		iSnError =1; break;
	}
	if(iSnError ==0) //备份的SN正确
	{
		memcpy(g_flash_sn->buff,bk_flash_sn->buff,g_flash_sn->size);
		save_data_to_file(g_flash_sn);
	}
	else //备份的SN也错误，随机生成
	{
		int iTick =(int)(LOS_TickCountGet()%100000000);
		sprintf((char *)(g_flash_sn->buff),"H0000%08d",iTick);
		sprintf((char *)(bk_flash_sn->buff),"H0000%08d",iTick);
		print_debug(0, "T_SN:%s\r\n", g_flash_sn->buff);
		save_data_to_file(bk_flash_sn);
		save_data_to_file(g_flash_sn);
	}
	memcpy(g_mcu_sn, bk_flash_sn->buff, bk_flash_sn->size);
	free_w25flash_t(&bk_flash_sn);
	free_w25flash_t(&g_flash_sn);
}

static void test_flash() //测试flash
{
	return;
	if(0) //ERASE_W25QXX
	{
		omip_printf(OMIP_ERROR,"begin to erase W25QXX flash Chip!!!\r\n");
		W25QXX_Erase_Chip();
		omip_printf(OMIP_ERROR,"erase W25QXX flash Chip succ!!!\r\n");
	}
}

void mcu_user_demo_entry(void *uwArg)
{
    omip_shakehand_sync sync = {0};
    omip_transaction recv_ts = {0};
    unsigned int i =(unsigned int)(uintptr_t)uwArg;
	OMIP_LOG_INFO("%s task(%d) start!!!", __FUNCTION__, LOS_CurTaskIDGet());
	
    if(i >(sizeof(g_common_conf)/(sizeof(struct omip_app_conf)))) return;
    omip_printf(OMIP_INFO,"mcu_user_demo start(index:%d),waiting guarding time(%d s). ...\r\n",i,(OMIP_GUARD_DELAY/1000));
    //osal_task_sleep(OMIP_GUARD_DELAY);
    int ret =omip_open_vc(g_common_conf[i].vc,g_common_conf[i].qos,g_common_conf[i].appname,g_common_conf[i].support_auth);
    if(ret <0) {omip_printf(OMIP_ERROR,"init vc(%d) failed!\r\n",g_common_conf[i].vc); return;}
    if(g_common_conf[i].support_auth ==1)
	{
        app_session *app_s = omip_malloc(sizeof(*app_s));
        if(app_s ==NULL) return;
        memset_s(app_s,sizeof(*app_s),0,sizeof(*app_s));
        omip_set_app_s(g_common_conf[i].vc, app_s);
    }
    if(g_common_conf[i].qos ==OMIP_QOS_2)
    {
        sync.vc = g_common_conf[i].vc;
        sync.data = g_common_conf[i].recv_buf;
        sync.len = OMIP_USER_RECV_BUF;
        sync.reconnect_flag = 0;
        sync.timeout = 1000*2;
        omip_shakehand(&sync);
    }
    if(g_common_conf[i].vc ==OMIP_VC_CHANNEL6) //设置蓝牙名称
    {
		g_flash_sn = file_addr_init("bksn", FILE_BL_BKSN_ADDR, FILE_BL_BKSN_SIZE);
		g_flash_sn->buff = (char *)malloc(sizeof(uint8_t)*g_flash_sn->size);
		read_data_from_file(g_flash_sn);
		set_ble_name(g_flash_sn->buff);
		free_w25flash_t(&g_flash_sn);
    }
    recv_ts.vc         = g_common_conf[i].vc;
    recv_ts.relay_flag = 0;
    recv_ts.relay_vc   = 0;
    recv_ts.timeout    = OMIP_RECV_DEFAULT;
    recv_ts.data       = g_common_conf[i].recv_buf;
    recv_ts.len        = sizeof(g_common_conf[i].recv_buf);
    if(i == 0) {check_sn(); test_flash(); send_update_bin_info();}
	
    while(1)
    {
		memset_s(recv_ts.data, recv_ts.len, 0, recv_ts.len);
        int len = omip_recv(&recv_ts); //阻塞接收（有超时）
        if(len < 0) {
			continue;
        }
        if(i == 0) //以太网HLINK消息
        {
	        if((g_common_conf[i].qos==OMIP_QOS_2) &&(recv_ts.cmd==OMIP_SYS_CMD_CONNECT)) {

				OMIP_LOG_INFO( "qos:%d, cmd:%d, len:%d",g_common_conf[i].qos, recv_ts.cmd, len);
				sync.reconnect_flag = 0; 
				omip_shakehand(&sync); 
				continue;
			}
	        omip_cmd_process_demo(recv_ts.vc, recv_ts.ctf, recv_ts.cmd, recv_ts.data, len);
        }
		else //蓝牙消息
		{
			omip_cmd_process_ble(recv_ts.vc, recv_ts.ctf, recv_ts.cmd,recv_ts.data,len);
		}
    }
}

void mcu_start_user_demo_task(void *arg)
{
	unsigned int i =(unsigned int)(uintptr_t)arg;
    char task_name[32] ={0};
    sprintf_s(task_name,sizeof(task_name)-1,"user_demo_task_%d",(int)(uintptr_t)arg);
    void *pid =osal_task_create(task_name,(int (*)(void *))mcu_user_demo_entry,arg,(i==0?(1024*16):(1024*8)),NULL,12);
    if(pid ==NULL) omip_printf(OMIP_ERROR,"[%s:%d]osal_task_create failed!\r\n",__FUNCTION__,__LINE__);
}

void mcu_start_local_flow_entry(void *uwArg)
{
	OMIP_LOG_INFO("%s task(%d) start!!!", __FUNCTION__, LOS_CurTaskIDGet());
	mcu_start_local_flow();
}

void mcu_start_local_flow_task(void *arg)
{
    void *pid =osal_task_create("start_local_flow",(int (*)(void *))mcu_start_local_flow_entry,arg,1024*2,NULL,12);
    if(pid ==NULL) omip_printf(OMIP_ERROR,"[%s:%d]osal_task_create failed!\r\n",__FUNCTION__,__LINE__);
}

void mcu_feed_watchdog_entry(void *uwArg) //喂狗函数
{
	OMIP_LOG_INFO("%s task(%d) start!!!", __FUNCTION__, LOS_CurTaskIDGet());
	while(1) {
		hal_iwdg_feed(); 
		LOS_TaskDelay(300);
	}
}

void mcu_start_user_watchdog_task(void *arg) //喂狗线程
{
    void *pid =osal_task_create("user_watchdog",(int (*)(void *))mcu_feed_watchdog_entry,arg,1024*1,NULL,12);
    if(pid ==NULL) omip_printf(OMIP_ERROR,"[%s:%d]osal_task_create failed!\r\n",__FUNCTION__,__LINE__);
}

void mcu_oper_hardware_entry(void *uwArg) //延时硬件操作函数
{
	int lstWFlashTime = 0; //上次写flash的时间
	int lstBeatheartTime = 0;
	int beatheart_flag = 0;
	OMIP_LOG_INFO("%s task(%d) start!!!", __FUNCTION__, LOS_CurTaskIDGet());
	while(1)
	{
		osal_task_sleep(1000);
		int curTime =LOS_Tick2MS(LOS_TickCountGet()); //当前时间
		if(abs(curTime-lstWFlashTime)>60000*60) //距离上次写入flash时间超过一定间隔
		{
			lstWFlashTime =curTime;
			if(vav_sumsta_ischanged() >0) vav_write_flash_status(); //vav累加状态有变化,写入FLASH中保存
		}
		if(wifi_need_reset() >0) //需要重启WIFI
		{
			osal_task_sleep(3000);
			wifi_reset();
		}
		if(system_need_reset() >0) //需要重启MCU
		{
		    int bin_flag =0x00;
			cmd_connect_beatheart(HLINK_OFFLINE);
			osal_task_sleep(3000);
            W25QXX_Read((uint8_t *)&bin_flag,FILE_BIN_FLAG_ADDR,FILE_FLAG_LENGTH);
            OMIP_LOG_INFO( "bin flag is:%02x restarting... \r\n", bin_flag);
            system_soft_reset();
		}

		//初次心跳，上报ONLINE
		if(0 == beatheart_flag && (abs(curTime-lstBeatheartTime) > 10000) ) {
			if(OMIP_OK == cmd_connect_beatheart(HLINK_ONLINE)) {
				beatheart_flag = 1;
			}
			lstBeatheartTime = curTime;
		}

		//与模组的心跳
		if((1 == beatheart_flag) && (abs(curTime-lstBeatheartTime) > 60000)) 
		{
			cmd_connect_beatheart(HLINK_REGISTERED);
			lstBeatheartTime = curTime;
		}
		
		//心跳超时，10次心跳没响应重启模组
		if(g_beatheart_timeout > 10) { 
			OMIP_LOG_ERROR("beatheart timeout, reset wifi or plc module");
			wifi_reset_delay();
			g_beatheart_timeout = 0;
		}

		
		
	}
}

void mcu_oper_hardware_task(void *arg) //延时硬件操作线程
{
    void *pid =osal_task_create("oper_hardware",(int (*)(void *))mcu_oper_hardware_entry,arg,1024*1,NULL,12);
    if(pid == NULL) {
		OMIP_LOG_ERROR("[%s:%d]osal_task_create failed!\r\n",__FUNCTION__,__LINE__);
    }
}

void mcu_demo_main(void) //用户主函数
{
	int ret = 0;
    cJSON_Hooks  hook;
    hook.free_fn = omip_free;
    hook.malloc_fn = omip_malloc;
    cJSON_InitHooks(&hook);
    omip_config_paras para = { 16, 1024 * 8 };
    ret = omip_module_install(&para);
	OMIP_LOG_INFO("omip module install ret=%d", ret);
	mcu_log_init();
	int cnt = 0;
	mcu_start_user_watchdog_task(NULL);

    while(W25QXX_ReadID() != W25Q128) //等待flash初始化
	{
		if(++cnt >= 300) {
			cnt =0; 
			OMIP_LOG_ERROR("[3s]wait for file system init \r\n");
		}
		osal_task_sleep(10);
    }
    OMIP_LOG_INFO("file system init succ(%d-%d) \r\n",PROCESS_THREAD_LIMIT,LOSCFG_BASE_CORE_TSK_LIMIT);
	mcu_oper_hardware_task(NULL);

#if OMIP_SUPPORT_PROXY
    omip_set_workmode(OMIP_WORK_PROXY);
    mcu_start_user_demo_task((void *)1);
    extern void ble8258_support_start(void);
    ble8258_support_start();
    extern void send_ble8258_frame(unsigned char *data, unsigned short len, int io_id);
    extern void recve_ble8258_byte(unsigned char data, int io_id);
    omip_set_inject_func(1, send_ble8258_frame, recve_ble8258_byte);
    omip_printf(OMIP_INFO,"OMIP_SUPPORT_PROXY, omip over ble8258!!!\r\n");
#else
    omip_set_workmode(OMIP_WORK_CONTROLER);
#endif
    mcu_start_user_demo_task((void *)0);
    //mcu_start_user_report_task();
    cengine_set_log_level(CENGINE_LOG_WARNING);
#ifndef LITE
    cengine_register_parse_status_callback(cengine_parse_status_callback);
    cengine_register_all_nodes();
#endif
	mcu_start_local_flow_task((void *)0);
    int erase_bin_flag = 0x00;
    W25QXX_Write((uint8_t *)&erase_bin_flag, FILE_BIN_FLAG_ADDR , FILE_FLAG_LENGTH);
#if CONFIG_BLE_ENABLE
    //extern int ble_task_start(void);
    //ble_task_start();
#endif
    LED_SYS_NORMAL_(LED_OPEN);
}

